/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
/******************************************************************************
*
* This software module was originally developed by
*
* Robert Danielsen (Telenor / ACTS-MoMuSys).
*
* and edited by
*
* Luis Ducla-Soares (IST / ACTS-MoMuSys).
* Cor Quist (KPN / ACTS-MoMuSys).
*
* in the course of development of the MPEG-4 Video (ISO/IEC 14496-2) standard.
* This software module is an implementation of a part of one or more MPEG-4
* Video (ISO/IEC 14496-2) tools as specified by the MPEG-4 Video (ISO/IEC
* 14496-2) standard.
*
* ISO/IEC gives users of the MPEG-4 Video (ISO/IEC 14496-2) standard free
* license to this software module or modifications thereof for use in hardware
* or software products claiming conformance to the MPEG-4 Video (ISO/IEC
* 14496-2) standard.
*
* Those intending to use this software module in hardware or software products
* are advised that its use may infringe existing patents. The original
* developer of this software module and his/her company, the subsequent
* editors and their companies, and ISO/IEC have no liability for use of this
* software module or modifications thereof in an implementation. Copyright is
* not released for non MPEG-4 Video (ISO/IEC 14496-2) standard conforming
* products.
*
* ACTS-MoMuSys partners retain full right to use the code for his/her own
* purpose, assign or donate the code to a third party and to inhibit third
* parties from using the code for non MPEG-4 Video (ISO/IEC 14496-2) standard
* conforming products. This copyright notice must be included in all copies or
* derivative works.
*
* Copyright (c) 1997
*
*****************************************************************************/

/***********************************************************HeaderBegin*******
*
* File: putvlc.c
*
* Author:   Robert Danielsen, Telenor R&D
* Created:  07.07.96
*
* Description: Functions for writing to bitstream
*
* Notes:    Same kind of tables as in the MPEG-2 software simulation
*       group software.
*
* Modified:
*   28.10.96 Robert Danielsen: Added PutCoeff_Intra(), renamed
*           PutCoeff() to PutCoeff_Inter().
*   06.11.96 Robert Danielsen: Added PutMCBPC_sep()
*      01.05.97 Luis Ducla-Soares: added PutCoeff_Intra_RVLC() and
*                                  PutCoeff_Inter_RVLC().
*
***********************************************************HeaderEnd*********/

/************************    INCLUDE FILES    ********************************/


#include "mp4lib_int.h"
#include "mp4enc_lib.h"
#include "vlc_enc_tab.h"
#include "bitstream_io.h"
#include "m4venc_oscl.h"
#include "vlc_encode_inline.h"

typedef void (*BlockCodeCoeffPtr)(RunLevelBlock*, BitstreamEncVideo*, Int, Int, UChar) ;

const static Int mode_MBtype[] =
{
    3,
    0,
    4,
    1,
    2,
};

const static Int zigzag_inv[NCOEFF_BLOCK] =
{
    0,  1,  8, 16,  9,  2,  3, 10,
    17, 24, 32, 25, 18, 11,  4,  5,
    12, 19, 26, 33, 40, 48, 41, 34,
    27, 20, 13,  6,  7, 14, 21, 28,
    35, 42, 49, 56, 57, 50, 43, 36,
    29, 22, 15, 23, 30, 37, 44, 51,
    58, 59, 52, 45, 38, 31, 39, 46,
    53, 60, 61, 54, 47, 55, 62, 63
};

/* Horizontal zigzag inverse */
const static Int zigzag_h_inv[NCOEFF_BLOCK] =
{
    0, 1, 2, 3, 8, 9, 16, 17,
    10, 11, 4, 5, 6, 7, 15, 14,
    13, 12, 19, 18, 24, 25, 32, 33,
    26, 27, 20, 21, 22, 23, 28, 29,
    30, 31, 34, 35, 40, 41, 48, 49,
    42, 43, 36, 37, 38, 39, 44, 45,
    46, 47, 50, 51, 56, 57, 58, 59,
    52, 53, 54, 55, 60, 61, 62, 63
};

/* Vertical zigzag inverse */
const static Int zigzag_v_inv[NCOEFF_BLOCK] =
{
    0, 8, 16, 24, 1, 9, 2, 10,
    17, 25, 32, 40, 48, 56, 57, 49,
    41, 33, 26, 18, 3, 11, 4, 12,
    19, 27, 34, 42, 50, 58, 35, 43,
    51, 59, 20, 28, 5, 13, 6, 14,
    21, 29, 36, 44, 52, 60, 37, 45,
    53, 61, 22, 30, 7, 15, 23, 31,
    38, 46, 54, 62, 39, 47, 55, 63
};

#ifdef __cplusplus
extern "C"
{
#endif

    Int PutCoeff_Inter(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutCoeff_Inter_Last(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutCoeff_Intra(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutCoeff_Intra_Last(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutCBPY(Int cbpy, Char intra, BitstreamEncVideo *bitstream);
    Int PutMCBPC_Inter(Int cbpc, Int mode, BitstreamEncVideo *bitstream);
    Int PutMCBPC_Intra(Int cbpc, Int mode, BitstreamEncVideo *bitstream);
    Int PutMV(Int mvint, BitstreamEncVideo *bitstream);
    Int PutDCsize_chrom(Int size, BitstreamEncVideo *bitstream);
    Int PutDCsize_lum(Int size, BitstreamEncVideo *bitstream);
    Int PutDCsize_lum(Int size, BitstreamEncVideo *bitstream);
#ifndef NO_RVLC
    Int PutCoeff_Inter_RVLC(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutCoeff_Inter_RVLC_Last(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutCoeff_Intra_RVLC(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutCoeff_Intra_RVLC_Last(Int run, Int level, BitstreamEncVideo *bitstream);
#endif
    Int PutRunCoeff_Inter(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutRunCoeff_Inter_Last(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutRunCoeff_Intra(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutRunCoeff_Intra_Last(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutLevelCoeff_Inter(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutLevelCoeff_Inter_Last(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutLevelCoeff_Intra(Int run, Int level, BitstreamEncVideo *bitstream);
    Int PutLevelCoeff_Intra_Last(Int run, Int level, BitstreamEncVideo *bitstream);

    void RunLevel(VideoEncData *video, Int intra, Int intraDC_decision, Int ncoefblck[]);
    Int IntraDC_dpcm(Int val, Int lum, BitstreamEncVideo *bitstream);
    Void DCACPred(VideoEncData *video, UChar Mode, Int *intraDC_decision, Int intraDCVlcQP);
    Void find_pmvs(VideoEncData *video, Int block, Int *mvx, Int *mvy);
    Void  WriteMVcomponent(Int f_code, Int dmv, BitstreamEncVideo *bs);
    static Bool IntraDCSwitch_Decision(Int Mode, Int intra_dc_vlc_threshold, Int intraDCVlcQP);

    Void ScaleMVD(Int  f_code, Int  diff_vector, Int  *residual, Int  *vlc_code_mag);

#ifdef __cplusplus
}
#endif

Int
PutDCsize_lum(Int size, BitstreamEncVideo *bitstream)
{
    Int length;

    if (!(size >= 0 && size < 13))
        return -1;

    length = DCtab_lum[size].len;
    if (length)
        BitstreamPutBits(bitstream, length, DCtab_lum[size].code);

    return length;
}

Int
PutDCsize_chrom(Int size, BitstreamEncVideo *bitstream)
{
    Int length;

    if (!(size >= 0 && size < 13))
        return -1;
    length = DCtab_chrom[size].len;
    if (length)
        BitstreamPutBits(bitstream, length, DCtab_chrom[size].code);

    return length;
}

Int
PutMV(Int mvint, BitstreamEncVideo *bitstream)
{
    Int sign = 0;
    Int absmv;
    Int length;

    if (mvint > 32)
    {
        absmv = -mvint + 65;
        sign = 1;
    }
    else
        absmv = mvint;

    length = mvtab[absmv].len;
    if (length)
        BitstreamPutBits(bitstream, length, mvtab[absmv].code);

    if (mvint != 0)
    {
        BitstreamPut1Bits(bitstream, sign);
        return (length + 1);
    }
    else
        return length;
}

Int
PutMCBPC_Intra(Int cbp, Int mode, BitstreamEncVideo *bitstream)
{
    Int ind;
    Int length;

    ind = ((mode_MBtype[mode] >> 1) & 3) | ((cbp & 3) << 2);

    length = mcbpc_intra_tab[ind].len;
    if (length)
        BitstreamPutBits(bitstream, length, mcbpc_intra_tab[ind].code);

    return length;
}

Int
PutMCBPC_Inter(Int cbp, Int mode, BitstreamEncVideo *bitstream)
{
    Int ind;
    Int length;

    ind = (mode_MBtype[mode] & 7) | ((cbp & 3) << 3);

    length = mcbpc_inter_tab[ind].len;
    if (length)
        BitstreamPutBits(bitstream, length, mcbpc_inter_tab[ind].code);

    return length;
}

Int
PutCBPY(Int cbpy, Char intra, BitstreamEncVideo *bitstream)
{
    Int ind;
    Int length;

    if (intra == 0)
        cbpy = 15 - cbpy;

    ind = cbpy;

    length = cbpy_tab[ind].len;
    if (length)
        BitstreamPutBits(bitstream, length, (UInt)cbpy_tab[ind].code);

    return length;
}

/* 5/16/01, break up function for last and not-last coefficient */
/* Note:::: I checked the ARM assembly for if( run > x && run < y) type
    of code, they do a really good job compiling it to if( (UInt)(run-x) < y-x).
    No need to hand-code it!!!!!, 6/1/2001 */

Int PutCoeff_Inter(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run < 2 && level < 13)
    {
        length = coeff_tab0[run][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab0[run][level-1].code);
    }
    else if (run > 1 && run < 27 && level < 5)
    {
        length = coeff_tab1[run-2][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab1[run-2][level-1].code);
    }

    return length;
}

Int PutCoeff_Inter_Last(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run < 2 && level < 4)
    {
        length = coeff_tab2[run][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab2[run][level-1].code);
    }
    else if (run > 1 && run < 42 && level == 1)
    {
        length = coeff_tab3[run-2].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab3[run-2].code);
    }

    return length;
}

/* 5/16/01, break up function for last and not-last coefficient */

Int PutCoeff_Intra(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run == 0 && level < 28)
    {
        length = coeff_tab4[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab4[level-1].code);
    }
    else if (run == 1 && level < 11)
    {
        length = coeff_tab5[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab5[level-1].code);
    }
    else if (run > 1 && run < 10 && level < 6)
    {
        length = coeff_tab6[run-2][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab6[run-2][level-1].code);
    }
    else if (run > 9 && run < 15 && level == 1)
    {
        length = coeff_tab7[run-10].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab7[run-10].code);
    }

    return length;
}

Int PutCoeff_Intra_Last(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run == 0 && level < 9)
    {
        length = coeff_tab8[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab8[level-1].code);
    }
    else if (run > 0 && run < 7 && level < 4)
    {
        length = coeff_tab9[run-1][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab9[run-1][level-1].code);
    }
    else if (run > 6 && run < 21 && level == 1)
    {
        length = coeff_tab10[run-7].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab10[run-7].code);
    }

    return length;
}

/* 5/16/01, break up function for last and not-last coefficient */
#ifndef NO_RVLC
Int PutCoeff_Inter_RVLC(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run == 0 && level < 20)
    {
        length =  coeff_RVLCtab14[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab14[level-1].code);
    }
    else if (run == 1 && level < 11)
    {
        length = coeff_RVLCtab15[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab15[level-1].code);
    }
    else if (run > 1 && run < 4 && level < 8)
    {
        length = coeff_RVLCtab16[run-2][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab16[run-2][level-1].code);
    }
    else if (run == 4 && level < 6)
    {
        length = coeff_RVLCtab17[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab17[level-1].code);
    }
    else if (run > 4 && run < 8 && level < 5)
    {
        length = coeff_RVLCtab18[run-5][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab18[run-5][level-1].code);
    }
    else if (run > 7 && run < 10 && level < 4)
    {
        length = coeff_RVLCtab19[run-8][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab19[run-8][level-1].code);
    }
    else if (run > 9 && run < 18 && level < 3)
    {
        length = coeff_RVLCtab20[run-10][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab20[run-10][level-1].code);
    }
    else if (run > 17 && run < 39 && level == 1)
    {
        length = coeff_RVLCtab21[run-18].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab21[run-18].code);
    }

    return length;
}

Int PutCoeff_Inter_RVLC_Last(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run >= 0 && run < 2 && level < 6)
    {
        length = coeff_RVLCtab22[run][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab22[run][level-1].code);
    }
    else if (run == 2 && level < 4)
    {
        length = coeff_RVLCtab23[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab23[level-1].code);
    }
    else if (run > 2 && run < 14 && level < 3)
    {
        length = coeff_RVLCtab24[run-3][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab24[run-3][level-1].code);
    }
    else if (run > 13 && run < 45 && level == 1)
    {
        length = coeff_RVLCtab25[run-14].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab25[run-14].code);
    }

    return length;
}

/* 5/16/01, break up function for last and not-last coefficient */

Int PutCoeff_Intra_RVLC(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run == 0 && level < 28)
    {
        length = coeff_RVLCtab1[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab1[level-1].code);
    }
    else if (run == 1 && level < 14)
    {
        length = coeff_RVLCtab2[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab2[level-1].code);
    }
    else if (run == 2 && level < 12)
    {
        length = coeff_RVLCtab3[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab3[level-1].code);
    }
    else if (run == 3 && level < 10)
    {
        length = coeff_RVLCtab4[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab4[level-1].code);
    }
    else if (run > 3 && run < 6 && level < 7)
    {
        length = coeff_RVLCtab5[run-4][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab5[run-4][level-1].code);
    }
    else if (run > 5 && run < 8 && level < 6)
    {
        length = coeff_RVLCtab6[run-6][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab6[run-6][level-1].code);
    }
    else if (run > 7 && run < 10 && level < 5)
    {
        length = coeff_RVLCtab7[run-8][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab7[run-8][level-1].code);

    }
    else if (run > 9 && run < 13 && level < 3)
    {
        length = coeff_RVLCtab8[run-10][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab8[run-10][level-1].code);
    }
    else if (run > 12 && run < 20 && level == 1)
    {
        length = coeff_RVLCtab9[run-13].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab9[run-13].code);
    }
    return length;
}

Int PutCoeff_Intra_RVLC_Last(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run >= 0 && run < 2 && level < 6)
    {
        length = coeff_RVLCtab10[run][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab10[run][level-1].code);
    }
    else if (run == 2 && level < 4)
    {
        length = coeff_RVLCtab11[level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab11[level-1].code);
    }
    else if (run > 2 && run < 14 && level < 3)
    {
        length = coeff_RVLCtab12[run-3][level-1].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab12[run-3][level-1].code);
    }
    else if (run > 13 && run < 45 && level == 1)
    {
        length = coeff_RVLCtab13[run-14].len;
        if (length)
            BitstreamPutBits(bitstream, length, (UInt)coeff_RVLCtab13[run-14].code);
    }
    return length;
}
#endif

/* The following is for 3-mode VLC */

Int
PutRunCoeff_Inter(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run < 2 && level < 13)
    {
        length = coeff_tab0[run][level-1].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab0[run][level-1].code);
            length += 9;
        }
    }
    else if (run > 1 && run < 27 && level < 5)
    {
        length = coeff_tab1[run-2][level-1].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab1[run-2][level-1].code);
            length += 9;
        }
    }
    return length;
}

Int PutRunCoeff_Inter_Last(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run < 2 && level < 4)
    {
        length = coeff_tab2[run][level-1].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab2[run][level-1].code);
            length += 9;
        }
    }
    else if (run > 1 && run < 42 && level == 1)
    {
        length = coeff_tab3[run-2].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab3[run-2].code);
            length += 9;
        }
    }
    return length;
}

Int PutRunCoeff_Intra(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run == 0 && level < 28)
    {
        length = coeff_tab4[level-1].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab4[level-1].code);
            length += 9;
        }
    }
    else if (run == 1 && level < 11)
    {
        length = coeff_tab5[level-1].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab5[level-1].code);
            length += 9;
        }
    }
    else if (run > 1 && run < 10 && level < 6)
    {
        length = coeff_tab6[run-2][level-1].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab6[run-2][level-1].code);
            length += 9;
        }
    }
    else if (run > 9 && run < 15 && level == 1)
    {
        length = coeff_tab7[run-10].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab7[run-10].code);
            length += 9;
        }
    }
    return length;
}
Int PutRunCoeff_Intra_Last(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run == 0 && level < 9)
    {
        length = coeff_tab8[level-1].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab8[level-1].code);
            length += 9;
        }
    }
    else if (run > 0 && run < 7 && level < 4)
    {
        length = coeff_tab9[run-1][level-1].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab9[run-1][level-1].code);
            length += 9;
        }
    }
    else if (run > 6 && run < 21 && level == 1)
    {
        length = coeff_tab10[run-7].len;
        if (length)
        {
            BitstreamPutGT8Bits(bitstream, 7 + 2, 14/*3*/);
            //BitstreamPutBits(bitstream, 2, 2);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab10[run-7].code);
            length += 9;
        }
    }
    return length;
}

Int
PutLevelCoeff_Inter(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run < 2 && level < 13)
    {
        length = coeff_tab0[run][level-1].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab0[run][level-1].code);
            length += 8;
        }
    }
    else if (run > 1 && run < 27 && level < 5)
    {
        length = coeff_tab1[run-2][level-1].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab1[run-2][level-1].code);
            length += 8;
        }
    }
    return length;
}

Int PutLevelCoeff_Inter_Last(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run < 2 && level < 4)
    {
        length = coeff_tab2[run][level-1].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab2[run][level-1].code);
            length += 8;
        }
    }
    else if (run > 1 && run < 42 && level == 1)
    {
        length = coeff_tab3[run-2].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab3[run-2].code);
            length += 8;
        }
    }
    return length;
}

Int PutLevelCoeff_Intra(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run == 0 && level < 28)
    {
        length = coeff_tab4[level-1].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab4[level-1].code);
            length += 8;
        }
    }
    else if (run == 1 && level < 11)
    {
        length = coeff_tab5[level-1].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab5[level-1].code);
            length += 8;
        }
    }
    else if (run > 1 && run < 10 && level < 6)
    {
        length = coeff_tab6[run-2][level-1].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab6[run-2][level-1].code);
            length += 8;
        }
    }
    else if (run > 9 && run < 15 && level == 1)
    {
        length = coeff_tab7[run-10].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab7[run-10].code);
            length += 8;
        }
    }
    return length;
}
Int PutLevelCoeff_Intra_Last(Int run, Int level, BitstreamEncVideo *bitstream)
{
    Int length = 0;

    if (run == 0 && level < 9)
    {
        length = coeff_tab8[level-1].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab8[level-1].code);
            length += 8;
        }
    }
    else if (run > 0 && run < 7 && level < 4)
    {
        length = coeff_tab9[run-1][level-1].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab9[run-1][level-1].code);
            length += 8;
        }
    }
    else if (run > 6 && run < 21 && level == 1)
    {
        length = coeff_tab10[run-7].len;
        if (length)
        {
            BitstreamPutBits(bitstream, 7 + 1, 6/*3*/);
            BitstreamPutBits(bitstream, length, (UInt)coeff_tab10[run-7].code);
            length += 8;
        }
    }
    return length;
}



/* ======================================================================== */
/*  Function : MBVlcEncode()                                                */
/*  Date     : 09/10/2000                                                   */
/*  Purpose  : Encode GOV Header                                            */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/*  Modified : 5/21/01, break up into smaller functions                     */
/* ======================================================================== */
#ifndef H263_ONLY
/**************************************/
/* Data Partitioning I-VOP Encoding   */
/**************************************/

void MBVlcEncodeDataPar_I_VOP(
    VideoEncData *video,
    Int ncoefblck[],
    void *blkCodePtr)
{

    BitstreamEncVideo *bs1 = video->bitstream1;
    BitstreamEncVideo *bs2 = video->bitstream2;
    BitstreamEncVideo *bs3 = video->bitstream3;
    int i;
    UChar Mode = video->headerInfo.Mode[video->mbnum];
    UChar CBP;
//  MacroBlock *MB=video->outputMB;
    Int mbnum = video->mbnum;
    Int intraDC_decision, DC;
//  int temp;
    Int dquant; /* 3/15/01 */
    RunLevelBlock *RLB = video->RLB;
    BlockCodeCoeffPtr BlockCodeCoeff = (BlockCodeCoeffPtr) blkCodePtr;

    /* DC and AC Prediction, 5/28/01, compute CBP, intraDC_decision*/
    DCACPred(video, Mode, &intraDC_decision, video->QP_prev);

    /* CBP, Run, Level, and Sign */
    RunLevel(video, 1, intraDC_decision, ncoefblck);
    CBP = video->headerInfo.CBP[mbnum];

    /* Compute DQuant */
    dquant = video->QPMB[mbnum] - video->QP_prev; /* 3/15/01, QP_prev may not equal QPMB[mbnum-1] if mbnum-1 is skipped*/

    video->QP_prev = video->QPMB[mbnum];

    if (dquant && Mode == MODE_INTRA)
    {
        Mode = MODE_INTRA_Q;
    }

    if (dquant >= 0)
        dquant = (PV_ABS(dquant) + 1);
    else
        dquant = (PV_ABS(dquant) - 1);

    /* FIRST PART: ALL TO BS1 */

    PutMCBPC_Intra(CBP, Mode, bs1); /* MCBPC */

    if (Mode == MODE_INTRA_Q)
        /*  MAY NEED TO CHANGE DQUANT HERE  */
        BitstreamPutBits(bs1, 2, dquant);  /* dquant*/


    if (intraDC_decision == 0)
    {
        for (i = 0; i < 6; i++)
        {
            DC = video->RLB[i].level[0];
            if (video->RLB[i].s[0])
                DC = -DC;
            if (i < 4)
                /*temp =*/ IntraDC_dpcm(DC, 1, bs1);        /* dct_dc_size_luminance, */
            else                                    /* dct_dc_differential, and */
                /*temp =*/ IntraDC_dpcm(DC, 0, bs1);        /* marker bit */
        }
    }

    /* SECOND PART: ALL TO BS2*/

    BitstreamPut1Bits(bs2, video->acPredFlag[video->mbnum]);    /* ac_pred_flag */

    /*temp=*/
    PutCBPY(CBP >> 2, (Char)(1), bs2); /* cbpy */


    /* THIRD PART:  ALL TO BS3*/
    /* MB_CodeCoeff(video,bs3); */ /* 5/22/01, replaced with below */
    for (i = 0; i < 6; i++)
    {
        if (CBP&(1 << (5 - i)))
            (*BlockCodeCoeff)(&(RLB[i]), bs3, 1 - intraDC_decision, ncoefblck[i], Mode);/* Code Intra AC*/
    }

    return ;
}

/************************************/
/* Data Partitioning P-VOP Encoding */
/************************************/

void MBVlcEncodeDataPar_P_VOP(
    VideoEncData *video,
    Int ncoefblck[],
    void *blkCodePtr)
{

    BitstreamEncVideo *bs1 = video->bitstream1;
    BitstreamEncVideo *bs2 = video->bitstream2;
    BitstreamEncVideo *bs3 = video->bitstream3;
    int i;
    Int mbnum = video->mbnum;
    UChar Mode = video->headerInfo.Mode[mbnum];
    Int QP_tmp = video->QPMB[mbnum];
    UChar CBP;
//  MacroBlock *MB=video->outputMB;
    Int intra, intraDC_decision, DC;
    Int pmvx, pmvy;
//  int temp;
    Int dquant; /* 3/15/01 */
    RunLevelBlock *RLB = video->RLB;
    BlockCodeCoeffPtr BlockCodeCoeff = (BlockCodeCoeffPtr) blkCodePtr;

    intra = (Mode == MODE_INTRA || Mode == MODE_INTRA_Q);

    /* DC and AC Prediction, 5/28/01, compute CBP, intraDC_decision*/

    if (intra)
    {
        if (video->usePrevQP)
        {
            QP_tmp = video->QPMB[mbnum-1];
        }

        DCACPred(video, Mode, &intraDC_decision, QP_tmp);
    }
    else
        intraDC_decision = 0; /* used in RunLevel */

    /* CBP, Run, Level, and Sign */
    RunLevel(video, intra, intraDC_decision, ncoefblck);
    CBP = video->headerInfo.CBP[mbnum];

    /* Compute DQuant */
    dquant = video->QPMB[mbnum] - video->QP_prev; /* 3/15/01, QP_prev may not equal QPMB[mbnum-1] if mbnum-1 is skipped*/

    if (dquant && (Mode == MODE_INTRA || Mode == MODE_INTER))
    {
        Mode += 2;  /* make it MODE_INTRA_Q and MODE_INTER_Q */
    }

    if (dquant >= 0)
        dquant = (PV_ABS(dquant) + 1);
    else
        dquant = (PV_ABS(dquant) - 1);

    /* FIRST PART: ALL TO BS1 */

    if (CBP == 0 && intra == 0)  /* Determine if Skipped MB */
    {
        if ((Mode == MODE_INTER) && (video->mot[mbnum][0].x == 0) && (video->mot[mbnum][0].y == 0))
            Mode = video->headerInfo.Mode[video->mbnum] = MODE_SKIPPED;
        else if ((Mode == MODE_INTER4V) && (video->mot[mbnum][1].x == 0) && (video->mot[mbnum][1].y == 0)
                 && (video->mot[mbnum][2].x == 0) && (video->mot[mbnum][2].y == 0)
                 && (video->mot[mbnum][3].x == 0) && (video->mot[mbnum][3].y == 0)
                 && (video->mot[mbnum][4].x == 0) && (video->mot[mbnum][4].y == 0))
            Mode = video->headerInfo.Mode[video->mbnum] = MODE_SKIPPED;
    }


    if (Mode == MODE_SKIPPED)
    {
        BitstreamPut1Bits(bs1, 1); /* not_coded = 1 */
        return;
    }
    else
        BitstreamPut1Bits(bs1, 0); /* not_coded =0 */

    video->QP_prev = video->QPMB[mbnum];
    video->usePrevQP = 1;

    PutMCBPC_Inter(CBP, Mode, bs1); /* MCBPC */

    video->header_bits -= BitstreamGetPos(bs1); /* Header Bits */

    if (Mode == MODE_INTER || Mode == MODE_INTER_Q)
    {
        find_pmvs(video, 0, &pmvx, &pmvy); /* Get predicted motion vectors */
        WriteMVcomponent(video->currVop->fcodeForward, video->mot[mbnum][0].x - pmvx, bs1); /* Write x to bitstream */
        WriteMVcomponent(video->currVop->fcodeForward, video->mot[mbnum][0].y - pmvy, bs1);     /* Write y to bitstream */
    }
    else if (Mode == MODE_INTER4V)
    {
        for (i = 1; i < 5; i++)
        {
            find_pmvs(video, i, &pmvx, &pmvy);
            WriteMVcomponent(video->currVop->fcodeForward, video->mot[mbnum][i].x - pmvx, bs1);
            WriteMVcomponent(video->currVop->fcodeForward, video->mot[mbnum][i].y - pmvy, bs1);
        }
    }
    video->header_bits += BitstreamGetPos(bs1); /* Header Bits */

    /* SECOND PART: ALL TO BS2 */


    if (intra)
    {
        BitstreamPut1Bits(bs2, video->acPredFlag[video->mbnum]);    /* ac_pred_flag */
        /*temp=*/
        PutCBPY(CBP >> 2, (Char)(Mode == MODE_INTRA || Mode == MODE_INTRA_Q), bs2); /* cbpy */

        if (Mode == MODE_INTRA_Q)
            BitstreamPutBits(bs2, 2, dquant);  /* dquant, 3/15/01*/

        if (intraDC_decision == 0)
        {
            for (i = 0; i < 6; i++)
            {
                DC = video->RLB[i].level[0];
                if (video->RLB[i].s[0])
                    DC = -DC;
                if (i < 4)
                    /*temp =*/ IntraDC_dpcm(DC, 1, bs2);        /* dct_dc_size_luminance, */
                else                                    /* dct_dc_differential, and */
                    /*temp =*/ IntraDC_dpcm(DC, 0, bs2);        /* marker bit */
            }
        }

        /****************************/  /* THIRD PART: ALL TO BS3 */
        for (i = 0; i < 6; i++)
        {
            if (CBP&(1 << (5 - i)))
                (*BlockCodeCoeff)(&(RLB[i]), bs3, 1 - intraDC_decision, ncoefblck[i], Mode);/* Code Intra AC*/
        }
    }
    else
    {
        /*temp=*/
        PutCBPY(CBP >> 2, (Char)(Mode == MODE_INTRA || Mode == MODE_INTRA_Q), bs2); /* cbpy */
        if (Mode == MODE_INTER_Q)
            /*  MAY NEED TO CHANGE DQUANT HERE  */
            BitstreamPutBits(bs2, 2, dquant);  /* dquant, 3/15/01*/

        /****************************/  /* THIRD PART: ALL TO BS3 */
        for (i = 0; i < 6; i++)
        {
            if (CBP&(1 << (5 - i)))
                (*BlockCodeCoeff)(&(RLB[i]), bs3, 0, ncoefblck[i], Mode);/* Code Intra AC*/
        }
    }

    return ;
}
#endif /* H263_ONLY */
/****************************************************************************************/
/* Short Header/Combined Mode with or without Error Resilience I-VOP and P-VOP Encoding */
/* 5/21/01, B-VOP is not implemented yet!!!!                                            */
/****************************************************************************************/

void MBVlcEncodeCombined_I_VOP(
    VideoEncData *video,
    Int ncoefblck[],
    void *blkCodePtr)
{

    BitstreamEncVideo *bs1 = video->bitstream1;
//  BitstreamEncVideo *bs2 = video->bitstream2;
//  BitstreamEncVideo *bs3 = video->bitstream3;
    int i;
    UChar Mode = video->headerInfo.Mode[video->mbnum];
    UChar CBP = video->headerInfo.CBP[video->mbnum];
//  MacroBlock *MB=video->outputMB;
    Int mbnum = video->mbnum;
    Int intraDC_decision;
//  int temp;
    Int dquant; /* 3/15/01 */
    RunLevelBlock *RLB = video->RLB;
    Int DC;
    Int shortVideoHeader = video->vol[video->currLayer]->shortVideoHeader;
    BlockCodeCoeffPtr BlockCodeCoeff = (BlockCodeCoeffPtr) blkCodePtr;

    /* DC and AC Prediction, 5/28/01, compute CBP, intraDC_decision*/

#ifndef H263_ONLY
    if (!shortVideoHeader)
        DCACPred(video, Mode, &intraDC_decision, video->QP_prev);
    else
#endif
    {
        intraDC_decision = 0;
    }

    /* CBP, Run, Level, and Sign */

    RunLevel(video, 1, intraDC_decision, ncoefblck);
    CBP = video->headerInfo.CBP[mbnum];

    /* Compute DQuant */
    dquant = video->QPMB[mbnum] - video->QP_prev; /* 3/15/01, QP_prev may not equal QPMB[mbnum-1] if mbnum-1 is skipped*/

    video->QP_prev = video->QPMB[mbnum];

    if (dquant && Mode == MODE_INTRA)
    {
        Mode = MODE_INTRA_Q;
    }

    if (dquant >= 0)
        dquant = (PV_ABS(dquant) + 1);
    else
        dquant = (PV_ABS(dquant) - 1);

    PutMCBPC_Intra(CBP, Mode, bs1); /* mcbpc I_VOP */

    if (!video->vol[video->currLayer]->shortVideoHeader)
    {
        BitstreamPut1Bits(bs1, video->acPredFlag[video->mbnum]);    /* ac_pred_flag */
    }

    /*temp=*/
    PutCBPY(CBP >> 2, (Char)(1), bs1); /* cbpy */

    if (Mode == MODE_INTRA_Q)
        /*  MAY NEED TO CHANGE DQUANT HERE */
        BitstreamPutBits(bs1, 2, dquant);  /* dquant, 3/15/01*/

    /*MB_CodeCoeff(video,bs1); 5/21/01, replaced by below */
    /*******************/
#ifndef H263_ONLY
    if (shortVideoHeader) /* Short Header DC coefficients */
    {
#endif
        for (i = 0; i < 6; i++)
        {
            DC = RLB[i].level[0];
            if (RLB[i].s[0])
                DC = -DC;
            if (DC != 128)
                BitstreamPutBits(bs1, 8, DC);   /* intra_dc_size_luminance */
            else
                BitstreamPutBits(bs1, 8, 255);          /* intra_dc_size_luminance */
            if (CBP&(1 << (5 - i)))
                (*BlockCodeCoeff)(&(RLB[i]), bs1, 1, ncoefblck[i], Mode); /* Code short header Intra AC*/
        }
#ifndef H263_ONLY
    }
    else if (intraDC_decision == 0)   /* Combined Intra Mode DC and AC coefficients */
    {
        for (i = 0; i < 6; i++)
        {
            DC = RLB[i].level[0];
            if (RLB[i].s[0])
                DC = -DC;

            if (i < 4)
                /*temp =*/ IntraDC_dpcm(DC, 1, bs1);        /* dct_dc_size_luminance, */
            else                                                /* dct_dc_differential, and */
                /*temp =*/ IntraDC_dpcm(DC, 0, bs1);        /* marker bit */
            if (CBP&(1 << (5 - i)))
                (*BlockCodeCoeff)(&(RLB[i]), bs1, 1, ncoefblck[i], Mode);/* Code Intra AC */
        }
    }
    else   /* Combined Mode Intra DC/AC coefficients */
    {
        for (i = 0; i < 6; i++)
        {
            if (CBP&(1 << (5 - i)))
                (*BlockCodeCoeff)(&(RLB[i]), bs1, 0, ncoefblck[i], Mode);/* Code Intra AC */
        }
    }
#endif
    /*******************/
    return ;
}

void MBVlcEncodeCombined_P_VOP(
    VideoEncData *video,
    Int ncoefblck[],
    void *blkCodePtr)
{

    BitstreamEncVideo *bs1 = video->bitstream1;
//  BitstreamEncVideo *bs2 = video->bitstream2;
//  BitstreamEncVideo *bs3 = video->bitstream3;
    int i;
    Int mbnum = video->mbnum;
    UChar Mode = video->headerInfo.Mode[mbnum];
    Int QP_tmp = video->QPMB[mbnum];
    UChar CBP ;
//  MacroBlock *MB=video->outputMB;
    Int intra, intraDC_decision;
    Int pmvx, pmvy;
//  int temp;
    Int dquant; /* 3/15/01 */
    RunLevelBlock *RLB = video->RLB;
    Int DC;
    Int shortVideoHeader = video->vol[video->currLayer]->shortVideoHeader;
    BlockCodeCoeffPtr BlockCodeCoeff = (BlockCodeCoeffPtr) blkCodePtr;

    intra = (Mode == MODE_INTRA || Mode == MODE_INTRA_Q);

    /* DC and AC Prediction, 5/28/01, compute intraDC_decision*/
#ifndef H263_ONLY
    if (!shortVideoHeader && intra)
    {
        if (video->usePrevQP)
        {
            QP_tmp = video->QPMB[mbnum-1];
        }
        DCACPred(video, Mode, &intraDC_decision, QP_tmp);
    }
    else
#endif
        intraDC_decision = 0;

    /* CBP, Run, Level, and Sign */

    RunLevel(video, intra, intraDC_decision, ncoefblck);
    CBP = video->headerInfo.CBP[mbnum];

    /* Compute DQuant */
    dquant = video->QPMB[mbnum] - video->QP_prev; /* 3/15/01, QP_prev may not equal QPMB[mbnum-1] if mbnum-1 is skipped*/
    if (dquant && (Mode == MODE_INTRA || Mode == MODE_INTER))
    {
        Mode += 2;  /* make it MODE_INTRA_Q and MODE_INTER_Q */
    }

    if (dquant >= 0)
        dquant = (PV_ABS(dquant) + 1);
    else
        dquant = (PV_ABS(dquant) - 1);

    if (CBP == 0 && intra == 0)  /* Determine if Skipped MB */
    {
        if ((Mode == MODE_INTER) && (video->mot[mbnum][0].x == 0) && (video->mot[mbnum][0].y == 0))
            Mode = video->headerInfo.Mode[video->mbnum] = MODE_SKIPPED;
        else if ((Mode == MODE_INTER4V) && (video->mot[mbnum][1].x == 0) && (video->mot[mbnum][1].y == 0)
                 && (video->mot[mbnum][2].x == 0) && (video->mot[mbnum][2].y == 0)
                 && (video->mot[mbnum][3].x == 0) && (video->mot[mbnum][3].y == 0)
                 && (video->mot[mbnum][4].x == 0) && (video->mot[mbnum][4].y == 0))
            Mode = video->headerInfo.Mode[video->mbnum] = MODE_SKIPPED;
    }

    if (Mode == MODE_SKIPPED)
    {
        BitstreamPut1Bits(bs1, 1); /* not_coded = 1 */
        return;
    }
    else
        BitstreamPut1Bits(bs1, 0); /* not_coded =0 */

    video->QP_prev = video->QPMB[mbnum];
    video->usePrevQP = 1;

    PutMCBPC_Inter(CBP, Mode, bs1); /* mcbpc P_VOP */

    if (!video->vol[video->currLayer]->shortVideoHeader && intra)
    {
        BitstreamPut1Bits(bs1, video->acPredFlag[video->mbnum]);    /* ac_pred_flag */
    }

    /*temp=*/
    PutCBPY(CBP >> 2, (Char)(intra), bs1); /* cbpy */

    if (Mode == MODE_INTRA_Q || Mode == MODE_INTER_Q)
        /*  MAY NEED TO CHANGE DQUANT HERE  */
        BitstreamPutBits(bs1, 2, dquant);  /* dquant, 3/15/01*/

    video->header_bits -= BitstreamGetPos(bs1); /* Header Bits */

    if (!((video->vol[video->currLayer]->scalability) && (video->currVop->refSelectCode == 3)))
    {
        if (Mode == MODE_INTER || Mode == MODE_INTER_Q)
        {
            find_pmvs(video, 0, &pmvx, &pmvy); /* Get predicted motion vectors */
            WriteMVcomponent(video->currVop->fcodeForward, video->mot[mbnum][0].x - pmvx, bs1); /* Write x to bitstream */
            WriteMVcomponent(video->currVop->fcodeForward, video->mot[mbnum][0].y - pmvy, bs1);     /* Write y to bitstream */
        }
        else if (Mode == MODE_INTER4V)
        {
            for (i = 1; i < 5; i++)
            {
                find_pmvs(video, i, &pmvx, &pmvy);
                WriteMVcomponent(video->currVop->fcodeForward, video->mot[mbnum][i].x - pmvx, bs1);
                WriteMVcomponent(video->currVop->fcodeForward, video->mot[mbnum][i].y - pmvy, bs1);
            }
        }
    }
    video->header_bits += BitstreamGetPos(bs1); /* Header Bits */

    /* MB_CodeCoeff(video,bs1); */ /* 5/22/01, replaced with below */
    /****************************/
    if (intra)
    {
#ifndef H263_ONLY
        if (shortVideoHeader) /* Short Header DC coefficients */
        {
#endif
            for (i = 0; i < 6; i++)
            {
                DC = RLB[i].level[0];
                if (RLB[i].s[0])
                    DC = -DC;
                if (DC != 128)
                    BitstreamPutBits(bs1, 8, DC);   /* intra_dc_size_luminance */
                else
                    BitstreamPutBits(bs1, 8, 255);          /* intra_dc_size_luminance */
                if (CBP&(1 << (5 - i)))
                    (*BlockCodeCoeff)(&(RLB[i]), bs1, 1, ncoefblck[i], Mode); /* Code short header Intra AC*/
            }
#ifndef H263_ONLY
        }
        else if (intraDC_decision == 0)   /* Combined Intra Mode DC and AC coefficients */
        {
            for (i = 0; i < 6; i++)
            {
                DC = RLB[i].level[0];
                if (RLB[i].s[0])
                    DC = -DC;

                if (i < 4)
                    /*temp =*/ IntraDC_dpcm(DC, 1, bs1);        /* dct_dc_size_luminance, */
                else                                                /* dct_dc_differential, and */
                    /*temp =*/ IntraDC_dpcm(DC, 0, bs1);        /* marker bit */
                if (CBP&(1 << (5 - i)))
                    (*BlockCodeCoeff)(&(RLB[i]), bs1, 1, ncoefblck[i], Mode);/* Code Intra AC */
            }
        }
        else   /* Combined Mode Intra DC/AC coefficients */
        {
            for (i = 0; i < 6; i++)
            {
                if (CBP&(1 << (5 - i)))
                    (*BlockCodeCoeff)(&(RLB[i]), bs1, 0, ncoefblck[i], Mode);/* Code Intra AC */
            }
        }
#endif
    }
    else   /* Shortheader or Combined INTER Mode AC coefficients */
    {
        for (i = 0; i < 6; i++)
        {
            if (CBP&(1 << (5 - i)))
                (*BlockCodeCoeff)(&(RLB[i]), bs1, 0, ncoefblck[i], Mode);/* Code Inter AC*/
        }
    }
    /****************************/

    return ;
}

/* ======================================================================== */
/*  Function : BlockCodeCoeff()                                         */
/*  Date     : 09/18/2000                                                   */
/*  Purpose  : VLC Encode  AC/DC coeffs                                     */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/*  Modified :  5/16/01  grouping BitstreamPutBits calls                    */
/*              5/22/01  break up function                              */
/* ======================================================================== */
#ifndef NO_RVLC
/*****************/
/* RVLC ENCODING */
/*****************/
Void BlockCodeCoeff_RVLC(RunLevelBlock *RLB, BitstreamEncVideo *bs, Int j_start, Int j_stop, UChar Mode)
{
    int length = 0;
    int i;
    Int level;
    Int run;
    Int intra = (Mode == MODE_INTRA || Mode == MODE_INTRA_Q);

    /* Not Last Coefficient */
    for (i = j_start; i < j_stop - 1; i++)
    {
        run = RLB->run[i];
        level = RLB->level[i];
        //if(i==63||RLB->run[i+1] == -1)    /* Don't Code Last Coefficient Here */
        //  break;
        /*ENCODE RUN LENGTH */
        if (level < 28 && run < 39)
        {
            if (intra)
                length = PutCoeff_Intra_RVLC(run, level, bs);
            else
                length = PutCoeff_Inter_RVLC(run, level, bs);
        }
        else
            length = 0;
        /* ESCAPE CODING */
        if (length == 0)
        {
            BitstreamPutBits(bs, 5 + 1, 2); /* ESCAPE + Not Last Coefficient */
            //BitstreamPutBits(bs,1,0); /* Not Last Coefficient */
            BitstreamPutBits(bs, 6 + 1, (run << 1) | 1); /* RUN + MARKER BIT*/
            //BitstreamPutBits(bs,1,1);  /* MARKER BIT */
            BitstreamPutGT8Bits(bs, 11, level); /* LEVEL */
            BitstreamPutBits(bs, 1 + 4, 16); /* MARKER BIT */
            //BitstreamPutBits(bs,4,0);  /* RVLC TRAILING ESCAPE */
        }
        BitstreamPutBits(bs, 1, RLB->s[i]); /* SIGN BIT */
    }
    /* Last Coefficient!!! */
    run = RLB->run[i];
    level = RLB->level[i];

    /*ENCODE RUN LENGTH */
    if (level < 6 && run < 45)
    {
        if (intra)
            length = PutCoeff_Intra_RVLC_Last(run, level, bs);
        else
            length = PutCoeff_Inter_RVLC_Last(run, level, bs);
    }
    else
        length = 0;
    /* ESCAPE CODING */
    if (length == 0)
    {
        BitstreamPutBits(bs, 5 + 1, 3); /* ESCAPE CODE + Last Coefficient*/
        //BitstreamPutBits(bs,1,1); /* Last Coefficient !*/
        BitstreamPutBits(bs, 6 + 1, (run << 1) | 1); /* RUN + MARKER BIT*/
        //BitstreamPutBits(bs,1,1);  /* MARKER BIT */
        BitstreamPutGT8Bits(bs, 11, level); /* LEVEL */
        BitstreamPutBits(bs, 1 + 4, 16); /* MARKER BIT + RVLC TRAILING ESCAPE */
        //BitstreamPutBits(bs,4,0);  /* */
    }
    BitstreamPut1Bits(bs, RLB->s[i]); /* SIGN BIT */

    return ;
}
#endif
/*******************************/
/* SHORT VIDEO HEADER ENCODING */
/*******************************/

Void BlockCodeCoeff_ShortHeader(RunLevelBlock *RLB, BitstreamEncVideo *bs, Int j_start, Int j_stop, UChar Mode)
{
    int length = 0;
    int i;
//  int temp;
    Int level;
    Int run;

    OSCL_UNUSED_ARG(Mode);

    /* Not Last Coefficient */
    for (i = j_start; i < j_stop - 1; i++)
    {
        run = RLB->run[i];
        level = RLB->level[i];
//      if(i==63 ||RLB->run[i+1] == -1) /* Don't Code Last Coefficient Here */
//          break;
        /*ENCODE RUN LENGTH */
        if (level < 13)
        {
            length = PutCoeff_Inter(run, level, bs);
            if (length != 0)
                /*temp =*/ BitstreamPut1Bits(bs, RLB->s[i]); /* Sign Bit */
        }
        else
            length = 0;
        /* ESCAPE CODING */
        if (length == 0)
        {
            if (RLB->s[i])
                level = -level;
            BitstreamPutBits(bs, 7 + 1, 6); /* ESCAPE CODE + Not Last Coefficient */
            //BitstreamPutBits(bs,1,0); /* Not Last Coefficient */
            BitstreamPutBits(bs, 6, run); /* RUN */
            BitstreamPutBits(bs, 8, level&0xFF); /* LEVEL, mask to make sure length 8 */
        }
    }
    /* Last Coefficient!!! */
    run = RLB->run[i];
    level = RLB->level[i];

    /*ENCODE RUN LENGTH */
    if (level < 13)
    {
        length = PutCoeff_Inter_Last(run, level, bs);
        if (length != 0)
            /*temp =*/ BitstreamPut1Bits(bs, RLB->s[i]); /* Sign Bit */
    }
    else
        length = 0;
    /* ESCAPE CODING */
    if (length == 0)
    {
        if (RLB->s[i])
            level = -level;
        BitstreamPutBits(bs, 7 + 1, 7); /* ESCAPE CODE + Last Coefficient */
        //BitstreamPutBits(bs,1,1); /* Last Coefficient !!!*/
        BitstreamPutBits(bs, 6, run); /* RUN */
        BitstreamPutBits(bs, 8, level&0xFF); /* LEVEL, mask to make sure length 8  */
    }

    return ;

}

#ifndef H263_ONLY
/****************/
/* VLC ENCODING */
/****************/
Void BlockCodeCoeff_Normal(RunLevelBlock *RLB, BitstreamEncVideo *bs, Int j_start, Int j_stop, UChar Mode)
{
    int length = 0;
    int i;
    //int temp;
    Int level;
    Int run;
    Int intra = (Mode == MODE_INTRA || Mode == MODE_INTRA_Q);
    Int level_minus_max;
    Int run_minus_max;
    Int(*PutCoeff)(Int, Int, BitstreamEncVideo *); /* pointer to functions, 5/28/01 */

    /* Not Last Coefficient!!! */

    if (intra)
        PutCoeff = &PutCoeff_Intra;
    else
        PutCoeff = &PutCoeff_Inter;

    for (i = j_start; i < j_stop - 1; i++)
    {
        run = RLB->run[i];
        level = RLB->level[i];

        /* Encode Run Length */
        if (level < 28)
        {
            length = (*PutCoeff)(run, level, bs); /* 5/28/01 replaces above */
        }
        else
        {
            length = 0;
        }

        /* First escape mode: LEVEL OFFSET */
        if (length == 0)
        {
            if (intra)
            {
                level_minus_max = level - intra_max_level[0][run];
                if (level_minus_max < 28)
                    length = PutLevelCoeff_Intra(run, level_minus_max, bs);
                else
                    length = 0;
            }
            else
            {
                level_minus_max = level - inter_max_level[0][run];
                if (level_minus_max < 13)
                    length = PutLevelCoeff_Inter(run, level_minus_max, bs);
                else
                    length = 0;
            }

            /* Second escape mode: RUN OFFSET */
            if (length == 0)
            {
                if (level < 28)
                {
                    if (intra)
                    {
                        run_minus_max = run - (intra_max_run0[level] + 1);
                        length = PutRunCoeff_Intra(run_minus_max, level, bs);
                    }
                    else if (level < 13)
                    {
                        run_minus_max = run - (inter_max_run0[level] + 1);
                        length = PutRunCoeff_Inter(run_minus_max, level, bs);
                    }
                    else
                    {
                        length = 0;
                    }
                }
                else
                {
                    length = 0;
                }

                /* Third escape mode: FIXED LENGTH CODE */
                if (length == 0)
                {
                    if (RLB->s[i])
                        level = -level;
                    /*temp =*/
                    BitstreamPutBits(bs, 7 + 2 + 1, 30); /* ESCAPE CODE + Followed by 11 + Not Last Coefficient*/
                    //temp = BitstreamPutBits(bs,2,3); /* Followed by 11 */
                    //temp = BitstreamPutBits(bs, 1, 0); /* Not Last Coefficient*/
                    /*temp =*/
                    BitstreamPutBits(bs, 6 + 1, (run << 1) | 1); /* Encode Run + Marker Bit */
                    //temp = BitstreamPutBits(bs,1,1); /* Marker Bit */
                    /*temp =*/
                    BitstreamPutGT8Bits(bs, 12 + 1, ((level << 1) | 1)&0x1FFF); /* Encode Level, mask to make sure length 12  */
                    //temp = BitstreamPutBits(bs,1,1); /* Marker Bit */
                }
            }
        }

        /* Encode Sign Bit */
        if (length != 0)
            /*temp =*/ BitstreamPut1Bits(bs, RLB->s[i]); /* Sign Bit */

    }
    /* Last Coefficient */
    run = RLB->run[i];
    level = RLB->level[i];

    /* Encode Run Length */
    if (level < 9)
    {
        if (intra)
        {
            length = PutCoeff_Intra_Last(run, level, bs);
        }
        else if (level < 4)
        {
            length = PutCoeff_Inter_Last(run, level, bs);
        }
        else
        {
            length = 0;
        }
    }
    else
    {
        length = 0;
    }

    /* First escape mode: LEVEL OFFSET */
    if (length == 0)
    {
        if (intra)
        {
            level_minus_max = level - intra_max_level[1][run];
            if (level_minus_max < 9)
                length = PutLevelCoeff_Intra_Last(run, level_minus_max, bs);
            else
                length = 0;
        }
        else
        {
            level_minus_max = level - inter_max_level[1][run];
            if (level_minus_max < 4)
                length = PutLevelCoeff_Inter_Last(run, level_minus_max, bs);
            else
                length = 0;
        }
        /* Second escape mode: RUN OFFSET */
        if (length == 0)
        {
            if (level < 9)
            {
                if (intra)
                {
                    run_minus_max = run - (intra_max_run1[level] + 1);
                    length = PutRunCoeff_Intra_Last(run_minus_max, level, bs);
                }
                else if (level < 4)
                {
                    run_minus_max = run - (inter_max_run1[level] + 1);
                    length = PutRunCoeff_Inter_Last(run_minus_max, level, bs);
                }
                else
                {
                    length = 0;
                }
            }
            else
            {
                length = 0;
            }
            /* Third escape mode: FIXED LENGTH CODE */
            if (length == 0)
            {
                if (RLB->s[i])
                    level = -level;
                /*temp =*/
                BitstreamPutGT8Bits(bs, 7 + 2 + 1, 31); /* ESCAPE CODE + Followed by 11 + Last Coefficient*/
                //temp = BitstreamPutBits(bs,2,3); /* Followed by 11 */
                //temp = BitstreamPutBits(bs, 1, 1); /* Last Coefficient!!!*/
                /*temp =*/
                BitstreamPutBits(bs, 6 + 1, (run << 1) | 1); /* Encode Run + Marker Bit */
                //temp = BitstreamPutBits(bs,1,1); /* Marker Bit */
                /*temp =*/
                BitstreamPutGT8Bits(bs, 12 + 1, ((level << 1) | 1)&0x1FFF); /* Encode Level, mask to make sure length 8 */
                //temp = BitstreamPutBits(bs,1,1); /* Marker Bit */
            }
        }
    }

    /* Encode Sign Bit */
    if (length != 0)
        /*temp =*/ BitstreamPut1Bits(bs, RLB->s[i]);


    return ;
}

#endif /* H263_ONLY */
/* ======================================================================== */
/*  Function : RUNLevel                                                     */
/*  Date     : 09/20/2000                                                   */
/*  Purpose  : Get the Coded Block Pattern for each block                   */
/*  In/out   :                                                              */
/*      Int* qcoeff     Quantized DCT coefficients
        Int Mode        Coding Mode
        Int ncoeffs     Number of coefficients                              */
/*  Return   :                                                              */
/*      Int CBP         Coded Block Pattern                                 */
/*  Modified :                                                              */
/* ======================================================================== */

void RunLevel(VideoEncData *video, Int intra, Int intraDC_decision, Int ncoefblck[])
{
    Int i, j;
    Int CBP = video->headerInfo.CBP[video->mbnum];
    Int ShortNacNintra = (!(video->vol[video->currLayer]->shortVideoHeader) && video->acPredFlag[video->mbnum] && intra);
    MacroBlock *MB = video->outputMB;
    Short *dataBlock;
    Int level;
    RunLevelBlock *RLB;
    Int run, idx;
    Int *zz, nc, zzorder;
    UChar imask[6] = {0x1F, 0x2F, 0x37, 0x3B, 0x3D, 0x3E};
    UInt *bitmapzz;

    /* Set Run, Level and CBP for this Macroblock */
    /* ZZ scan is done here.  */

    if (intra)
    {

        if (intraDC_decision != 0)
            intra = 0;              /* DC/AC in Run/Level */

        for (i = 0; i < 6 ; i++)
        {

            zz = (Int *) zigzag_inv;

            RLB = video->RLB + i;

            dataBlock = MB->block[i];

            if (intra)
            {
                RLB->run[0] = 0;
                level = dataBlock[0];
                dataBlock[0] = 0; /* reset to zero */
                if (level < 0)
                {
                    RLB->level[0] = -level;
                    RLB->s[0] = 1;
                }
                else
                {
                    RLB->level[0] = level;
                    RLB->s[0] = 0;
                }
            }

            idx = intra;

            if ((CBP >> (5 - i)) & 1)
            {
                if (ShortNacNintra)
                {
                    switch ((video->zz_direction >> (5 - i))&1)
                    {
                        case 0:
                            zz = (Int *)zigzag_v_inv;
                            break;
                        case 1:
                            zz = (Int *)zigzag_h_inv;
                            break;
                    }
                }
                run = 0;
                nc = ncoefblck[i];
                for (j = intra, zz += intra; j < nc; j++, zz++)
                {
                    zzorder = *zz;
                    level = dataBlock[zzorder];
                    if (level == 0)
                        run++;
                    else
                    {
                        dataBlock[zzorder] = 0; /* reset output */
                        if (level < 0)
                        {
                            RLB->level[idx] = -level;
                            RLB->s[idx] = 1;
                            RLB->run[idx] = run;
                            run = 0;
                            idx++;
                        }
                        else
                        {
                            RLB->level[idx] = level;
                            RLB->s[idx] = 0;
                            RLB->run[idx] = run;
                            run = 0;
                            idx++;
                        }
                    }
                }
            }

            ncoefblck[i] = idx; /* 5/22/01, reuse ncoefblck */

            if (idx == intra) /* reset CBP, nothing to be coded */
                CBP &= imask[i];
        }

        video->headerInfo.CBP[video->mbnum] = CBP;

        return ;
    }
    else
    {
//      zz = (Int *) zigzag_inv;  no need to use it, default

        if (CBP)
        {
            for (i = 0; i < 6 ; i++)
            {
                RLB = video->RLB + i;
                idx = 0;

                if ((CBP >> (5 - i)) & 1)
                {   /* 7/30/01 */
                    /* Use bitmapzz to find the Run,Level,Sign symbols */
                    bitmapzz = video->bitmapzz[i];
                    dataBlock = MB->block[i];
                    nc  = ncoefblck[i];

                    idx = zero_run_search(bitmapzz, dataBlock, RLB, nc);
                }
                ncoefblck[i] = idx; /* 5/22/01, reuse ncoefblck */
                if (idx == 0) /* reset CBP, nothing to be coded */
                    CBP &= imask[i];
            }
            video->headerInfo.CBP[video->mbnum] = CBP;
        }
        return ;
    }
}

#ifndef H263_ONLY
#ifdef __cplusplus
extern "C"
{
#endif
    static Bool IntraDCSwitch_Decision(Int Mode, Int intra_dc_vlc_thr, Int intraDCVlcQP)
    {
        Bool switched = FALSE;

        if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q)
        {
            if (intra_dc_vlc_thr != 0)
            {
                switched = (intra_dc_vlc_thr == 7 || intraDCVlcQP >= intra_dc_vlc_thr * 2 + 11);
            }
        }

        return switched;
    }
#ifdef __cplusplus
}
#endif

Int IntraDC_dpcm(Int val, Int lum, BitstreamEncVideo *bitstream)
{
    Int n_bits;
    Int absval, size = 0;

    absval = (val < 0) ? -val : val;    /* abs(val) */


    /* compute dct_dc_size */

    size = 0;
    while (absval)
    {
        absval >>= 1;
        size++;
    }

    if (lum)
    {   /* luminance */
        n_bits = PutDCsize_lum(size, bitstream);
    }
    else
    {   /* chrominance */
        n_bits = PutDCsize_chrom(size, bitstream);
    }

    if (size != 0)
    {
        if (val >= 0)
        {
            ;
        }
        else
        {
            absval = -val; /* set to "-val" MW 14-NOV-1996 */
            val = absval ^((1 << size) - 1);
        }
        BitstreamPutBits(bitstream, (size), (UInt)(val));
        n_bits += size;

        if (size > 8)
            BitstreamPut1Bits(bitstream, 1);
    }

    return n_bits;  /* # bits for intra_dc dpcm */

}

/* ======================================================================== */
/*  Function : DC_AC_PRED                                                   */
/*  Date     : 09/24/2000                                                   */
/*  Purpose  : DC and AC encoding of Intra Blocks                           */
/*  In/out   :                                                              */
/*      VideoEncData    *video
        UChar           Mode                                                */
/*  Return   :                                                              */
/*                                                                          */
/* ======================================================================== */
Int cal_dc_scalerENC(Int QP, Int type) ;


#define PREDICT_AC  for (m = 0; m < 7; m++){ \
                        tmp = DCAC[0]*QPtmp;\
                        if(tmp<0)   tmp = (tmp-(QP/2))/QP;\
                        else        tmp = (tmp+(QP/2))/QP;\
                        pred[m] = tmp;\
                        DCAC++;\
                    }


Void DCACPred(VideoEncData *video, UChar Mode, Int *intraDC_decision, Int intraDCVlcQP)
{
    MacroBlock *MB = video->outputMB;
    Int mbnum = video->mbnum;
    typeDCStore *DC_store = video->predDC + mbnum;
    typeDCACStore *DCAC_row = video->predDCAC_row;
    typeDCACStore *DCAC_col = video->predDCAC_col;
    Short   *DCAC;
    UChar Mode_top, Mode_left;

    Vol *currVol = video->vol[video->currLayer];
    Int nMBPerRow = currVol->nMBPerRow;
    Int x_pos = video->outputMB->mb_x; /* 5/28/01 */
    Int y_pos = video->outputMB->mb_y;
    UChar QP = video->QPMB[mbnum];
    UChar *QPMB = video->QPMB;
    UChar *slice_nb = video->sliceNo;
    Bool bACPredEnable = video->encParams->ACDCPrediction;
    Int *ACpred_flag = video->acPredFlag;
    Int mid_grey = 128 << 3;
    Int m;
    Int comp;
    Int dc_scale = 8, tmp;

    static const Int Xpos[6] = { -1, 0, -1, 0, -1, -1};
    static const Int Ypos[6] = { -1, -1, 0, 0, -1, -1};
    static const Int Xtab[6] = {1, 0, 3, 2, 4, 5};
    static const Int Ytab[6] = {2, 3, 0, 1, 4, 5};
    static const Int Ztab[6] = {3, 2, 1, 0, 4, 5};

    /* I added these to speed up comparisons */
    static const Int Pos0[6] = { 1, 1, 0, 0, 1, 1};
    static const Int Pos1[6] = { 1, 0, 1, 0, 1, 1};
    static const Int B_Xtab[6] = {0, 1, 0, 1, 2, 3};
    static const Int B_Ytab[6] = {0, 0, 1, 1, 2, 3};

    Int direction[6];       /* 0: HORIZONTAL, 1: VERTICAL */
    Int block_A, block_B, block_C;
    Int grad_hor, grad_ver, DC_pred;
    Short pred[7], *predptr;
    Short pcoeff[42];
    Short *qcoeff;
    Int S = 0, S1, S2;
    Int diff, QPtmp;
    Int newCBP[6];
    UChar mask1[6] = {0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
//  UChar mask2[6] = {0x1f,0x2f,0x37,0x3b,0x3d,0x3e};

    Int y_offset, x_offset, x_tab, y_tab, z_tab;    /* speedup coefficients */
    Int b_xtab, b_ytab;

    video->zz_direction = 0;

    /* Standard MPEG-4 Headers do DC/AC prediction*/
    /* check whether neighbors are INTER */
    if (y_pos > 0)
    {
        Mode_top = video->headerInfo.Mode[mbnum-nMBPerRow];
        if (!(Mode_top == MODE_INTRA || Mode_top == MODE_INTRA_Q))
        {
            DCAC = DC_store[-nMBPerRow];
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            /* set to 0 DCAC_row[x_pos][0..3] */
            if (bACPredEnable == TRUE)
            {
                M4VENC_MEMSET(DCAC_row[x_pos][0], 0, sizeof(Short) << 5);
            }
        }
    }
    if (x_pos > 0)
    {
        Mode_left = video->headerInfo.Mode[mbnum-1];
        if (!(Mode_left == MODE_INTRA || Mode_left == MODE_INTRA_Q))
        {
            DCAC = DC_store[-1];
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            *DCAC++ = mid_grey;
            /* set to 0 DCAC_col[x_pos][0..3] */
            if (bACPredEnable == TRUE)
            {
                M4VENC_MEMSET(DCAC_col[0][0], 0, sizeof(Short) << 5);
            }
        }
    }

    S1 = 0;
    S2 = 0;

    for (comp = 0; comp < 6; comp++)
    {

        if (Ypos[comp] != 0)        y_offset = -nMBPerRow;
        else                    y_offset = 0;
        x_offset = Xpos[comp];
        x_tab = Xtab[comp];
        y_tab = Ytab[comp];
        z_tab = Ztab[comp];

        b_xtab = B_Xtab[comp];
        b_ytab = B_Ytab[comp];

        qcoeff = MB->block[comp];

        /****************************/
        /*  Store DC coefficients */
        /****************************/
        /* Store coeff values for Intra MB */
        if (comp == 0) dc_scale = cal_dc_scalerENC(QP, 1) ;
        if (comp == 4) dc_scale = cal_dc_scalerENC(QP, 2) ;

        QPtmp = qcoeff[0] * dc_scale; /* DC value */

        if (QPtmp > 2047)   /* 10/10/01, add clipping (bug fixed) */
            DC_store[0][comp] = 2047;
        else if (QPtmp < -2048)
            DC_store[0][comp] = -2048;
        else
            DC_store[0][comp] = QPtmp;

        /**************************************************************/
        /* Find the direction of the prediction and the DC prediction */
        /**************************************************************/

        if ((x_pos == 0) && y_pos == 0)
        {   /* top left corner */
            block_A = (comp == 1 || comp == 3) ? DC_store[0][x_tab] : mid_grey;
            block_B = (comp == 3) ? DC_store[x_offset][z_tab] : mid_grey;
            block_C = (comp == 2 || comp == 3) ? DC_store[0][y_tab] : mid_grey;
        }
        else if (x_pos == 0)
        {   /* left edge */
            block_A = (comp == 1 || comp == 3) ? DC_store[0][x_tab] : mid_grey;
            block_B = ((comp == 1 && (slice_nb[mbnum] == slice_nb[mbnum-nMBPerRow])) || comp == 3) ?
                      DC_store[y_offset+x_offset][z_tab] : mid_grey;
            block_C = (comp == 2 || comp == 3 ||
                       (Pos0[comp] && (slice_nb[mbnum] == slice_nb[mbnum-nMBPerRow]))) ?
                      DC_store[y_offset][y_tab] : mid_grey;
        }
        else if (y_pos == 0)
        { /* top row */
            block_A = (comp == 1 || comp == 3 || (Pos1[comp] && (slice_nb[mbnum] == slice_nb[mbnum-1]))) ?
                      DC_store[x_offset][x_tab] : mid_grey;
            block_B = ((comp == 2 && (slice_nb[mbnum] == slice_nb[mbnum-1])) || comp == 3) ?
                      DC_store[y_offset + x_offset][z_tab] : mid_grey;
            block_C = (comp == 2 || comp == 3) ?
                      DC_store[y_offset][y_tab] : mid_grey;
        }
        else
        {
            block_A = (comp == 1 || comp == 3 || (Pos1[comp] && (slice_nb[mbnum] == slice_nb[mbnum-1]))) ?
                      DC_store[x_offset][x_tab] : mid_grey;
            block_B = (((comp == 0 || comp == 4 || comp == 5) &&
                        (slice_nb[mbnum] == slice_nb[mbnum-1-nMBPerRow])) ||
                       (comp == 1 && (slice_nb[mbnum] == slice_nb[mbnum-nMBPerRow])) ||
                       (comp == 2 && (slice_nb[mbnum] == slice_nb[mbnum-1])) || (comp == 3)) ?
                      (DC_store[y_offset + x_offset][z_tab]) : mid_grey;
            block_C = (comp == 2 || comp == 3 || (Pos0[comp] && (slice_nb[mbnum] == slice_nb[mbnum-nMBPerRow]))) ?
                      DC_store[y_offset][y_tab] : mid_grey;
        }
        grad_hor = block_B - block_C;
        grad_ver = block_A - block_B;

        if ((PV_ABS(grad_ver)) < (PV_ABS(grad_hor)))
        {
            DC_pred = block_C;
            direction[comp] = 1;
            video->zz_direction = (video->zz_direction) | mask1[comp];

        }
        else
        {
            DC_pred = block_A;
            direction[comp] = 0;
            //video->zz_direction=video->zz_direction<<1;
        }

        /* DC prediction */
        QPtmp = dc_scale; /* 5/28/01 */
        qcoeff[0] -= (DC_pred + QPtmp / 2) / QPtmp;


        if (bACPredEnable)
        {
            /***********************/
            /* Find AC prediction  */
            /***********************/

            if ((x_pos == 0) && y_pos == 0)     /* top left corner */
            {
                if (direction[comp] == 0)
                {
                    if (comp == 1 || comp == 3)
                    {
                        QPtmp = QPMB[mbnum+x_offset];
                        DCAC = DCAC_col[0][b_ytab];
                        if (QPtmp != QP)
                        {
                            predptr = pred;
                            PREDICT_AC
                        }
                        else
                        {
                            predptr = DCAC;
                        }
                    }
                    else
                    {
                        predptr = pred;
                        pred[0] = pred[1] = pred[2] = pred[3] = pred[4] = pred[5] = pred[6] = 0;
                    }
                }
                else
                {
                    if (comp == 2 || comp == 3)
                    {
                        QPtmp = QPMB[mbnum+ y_offset];
                        DCAC = DCAC_row[x_pos][b_xtab];
                        if (QPtmp != QP)
                        {
                            predptr = pred;
                            PREDICT_AC
                        }
                        else
                        {
                            predptr = DCAC;
                        }
                    }
                    else
                    {
                        predptr = pred;
                        pred[0] = pred[1] = pred[2] = pred[3] = pred[4] = pred[5] = pred[6] = 0;
                    }
                }
            }
            else if (x_pos == 0)    /* left edge */
            {
                if (direction[comp] == 0)
                {
                    if (comp == 1 || comp == 3)
                    {
                        QPtmp = QPMB[mbnum+x_offset];
                        DCAC = DCAC_col[0][b_ytab];
                        if (QPtmp != QP)
                        {
                            predptr = pred;
                            PREDICT_AC
                        }
                        else
                        {
                            predptr = DCAC;
                        }
                    }
                    else
                    {
                        predptr = pred;
                        pred[0] = pred[1] = pred[2] = pred[3] = pred[4] = pred[5] = pred[6] = 0;
                    }
                }
                else
                {

                    if ((Pos0[comp] && (slice_nb[mbnum] == slice_nb[mbnum-nMBPerRow]))
                            || comp == 2 || comp == 3)
                    {
                        QPtmp = QPMB[mbnum+y_offset];
                        DCAC = DCAC_row[x_pos][b_xtab];
                        if (QPtmp != QP)
                        {
                            predptr = pred;
                            PREDICT_AC
                        }
                        else
                        {
                            predptr = DCAC;
                        }
                    }
                    else
                    {
                        predptr = pred;
                        pred[0] = pred[1] = pred[2] = pred[3] = pred[4] = pred[5] = pred[6] = 0;
                    }
                }
            }
            else if (y_pos == 0)  /* top row */
            {
                if (direction[comp] == 0)
                {
                    if ((Pos1[comp] && (slice_nb[mbnum] == slice_nb[mbnum-1]))
                            || comp == 1 || comp == 3)
                    {
                        QPtmp = QPMB[mbnum+x_offset];
                        DCAC = DCAC_col[0][b_ytab];
                        if (QPtmp != QP)
                        {
                            predptr = pred;
                            PREDICT_AC
                        }
                        else
                        {
                            predptr = DCAC;
                        }
                    }
                    else
                    {
                        predptr = pred;
                        pred[0] = pred[1] = pred[2] = pred[3] = pred[4] = pred[5] = pred[6] = 0;
                    }
                }
                else
                {
                    if (comp == 2 || comp == 3)
                    {
                        QPtmp = QPMB[mbnum+y_offset];
                        DCAC = DCAC_row[x_pos][b_xtab];
                        if (QPtmp != QP)
                        {
                            predptr = pred;
                            PREDICT_AC
                        }
                        else
                        {
                            predptr = DCAC;
                        }
                    }
                    else
                    {
                        predptr = pred;
                        pred[0] = pred[1] = pred[2] = pred[3] = pred[4] = pred[5] = pred[6] = 0;
                    }
                }
            }
            else
            {
                if (direction[comp] == 0)
                {
                    if ((Pos1[comp] && (slice_nb[mbnum] == slice_nb[mbnum-1]))
                            || comp == 1 || comp == 3)
                    {
                        QPtmp = QPMB[mbnum+x_offset];
                        DCAC = DCAC_col[0][b_ytab];
                        if (QPtmp != QP)
                        {
                            predptr = pred;
                            PREDICT_AC
                        }
                        else
                        {
                            predptr = DCAC;
                        }
                    }
                    else
                    {
                        predptr = pred;
                        pred[0] = pred[1] = pred[2] = pred[3] = pred[4] = pred[5] = pred[6] = 0;
                    }
                }
                else
                {
                    if ((Pos0[comp] && (slice_nb[mbnum] == slice_nb[mbnum-nMBPerRow]))
                            || comp  == 2 || comp == 3)
                    {
                        QPtmp = QPMB[mbnum+y_offset];
                        DCAC = DCAC_row[x_pos][b_xtab];
                        if (QPtmp != QP)
                        {
                            predptr = pred;
                            PREDICT_AC
                        }
                        else
                        {
                            predptr = DCAC;
                        }
                    }
                    else
                    {
                        predptr = pred;
                        pred[0] = pred[1] = pred[2] = pred[3] = pred[4] = pred[5] = pred[6] = 0;
                    }
                }
            }

            /************************************/
            /* Decide and Perform AC prediction */
            /************************************/
            newCBP[comp] = 0;

            if (direction[comp] == 0)   /* Horizontal, left COLUMN of block A */
            {
                DCAC = pcoeff + comp * 7; /* re-use DCAC as local var */
                qcoeff += 8;
                for (m = 0; m < 7; m++)
                {
                    QPtmp = qcoeff[m<<3];
                    if (QPtmp > 0)  S1 += QPtmp;
                    else        S1 -= QPtmp;
                    QPtmp -= predptr[m];
                    DCAC[m] = QPtmp; /* save prediction residue to pcoeff*/
                    if (QPtmp)  newCBP[comp] = 1;
                    diff = PV_ABS(QPtmp);
                    S2 += diff;
                }
            }
            else            /* Vertical, top ROW of block C */
            {
                qcoeff++;
                DCAC = pcoeff + comp * 7; /* re-use DCAC as local var */
                for (m = 0; m < 7; m++)
                {
                    QPtmp = qcoeff[m];
                    if (QPtmp > 0)  S1 += QPtmp;
                    else        S1 -= QPtmp;
                    QPtmp -= predptr[m];
                    DCAC[m] = QPtmp; /* save prediction residue to pcoeff*/
                    if (QPtmp)  newCBP[comp] = 1;
                    diff = PV_ABS(QPtmp);
                    S2 += diff;
                }
            }

            /****************************/
            /*  Store DCAC coefficients */
            /****************************/
            /* Store coeff values for Intra MB */
            qcoeff = MB->block[comp];
            DCAC = DCAC_row[x_pos][b_xtab];
            DCAC[0] = qcoeff[1];
            DCAC[1] = qcoeff[2];
            DCAC[2] = qcoeff[3];
            DCAC[3] = qcoeff[4];
            DCAC[4] = qcoeff[5];
            DCAC[5] = qcoeff[6];
            DCAC[6] = qcoeff[7];

            DCAC = DCAC_col[0][b_ytab];
            DCAC[0] = qcoeff[8];
            DCAC[1] = qcoeff[16];
            DCAC[2] = qcoeff[24];
            DCAC[3] = qcoeff[32];
            DCAC[4] = qcoeff[40];
            DCAC[5] = qcoeff[48];
            DCAC[6] = qcoeff[56];


        } /* bACPredEnable */

    } /* END COMP FOR LOOP */

    //if (diff > 2047)
    //    break;
    S += (S1 - S2);


    if (S >= 0 && bACPredEnable == TRUE)
    {
        ACpred_flag[mbnum] = 1;
        DCAC = pcoeff; /* prediction residue */
        qcoeff = MB->block[0];

        for (comp = 0; comp < 6; comp++)
        {
            if (direction[comp] == 0)
            {
                qcoeff[8] = DCAC[0];
                qcoeff[16] = DCAC[1];
                qcoeff[24] = DCAC[2];
                qcoeff[32] = DCAC[3];
                qcoeff[40] = DCAC[4];
                qcoeff[48] = DCAC[5];
                qcoeff[56] = DCAC[6];

            }
            else
            {
                qcoeff[1] = DCAC[0];
                qcoeff[2] = DCAC[1];
                qcoeff[3] = DCAC[2];
                qcoeff[4] = DCAC[3];
                qcoeff[5] = DCAC[4];
                qcoeff[6] = DCAC[5];
                qcoeff[7] = DCAC[6];
            }
            if (newCBP[comp]) /* 5/28/01, update CBP */
                video->headerInfo.CBP[mbnum] |= mask1[comp];
            DCAC += 7;
            qcoeff += 64;
        }
    }
    else  /* Only DC Prediction */
    {
        ACpred_flag[mbnum] = 0;
    }

    *intraDC_decision = IntraDCSwitch_Decision(Mode, video->currVop->intraDCVlcThr, intraDCVlcQP);
    if (*intraDC_decision) /* code DC with AC , 5/28/01*/
    {
        qcoeff = MB->block[0];
        for (comp = 0; comp < 6; comp++)
        {
            if (*qcoeff)
                video->headerInfo.CBP[mbnum] |= mask1[comp];
            qcoeff += 64;
        }
    }
    return;
}
#endif /* H263_ONLY */



Void find_pmvs(VideoEncData *video, Int block, Int *mvx, Int *mvy)
{
    Vol *currVol = video->vol[video->currLayer];
//  UChar *Mode = video->headerInfo.Mode; /* modes for MBs */
    UChar *slice_nb = video->sliceNo;
    Int nMBPerRow = currVol->nMBPerRow;
    Int mbnum = video->mbnum;

    Int   p1x, p2x, p3x;
    Int   p1y, p2y, p3y;
    Int   xin1, xin2, xin3;
    Int   yin1, yin2, yin3;
    Int   vec1, vec2, vec3;
    Int   rule1, rule2, rule3;
    MOT   **motdata = video->mot;
    Int   x = mbnum % nMBPerRow;
    Int   y = mbnum / nMBPerRow;

    /*
        In a previous version, a MB vector (block = 0) was predicted the same way
        as block 1, which is the most likely interpretation of the VM.

        Therefore, if we have advanced pred. mode, and if all MBs around have
        only one 16x16 vector each, we chose the appropiate block as if these
        MBs have 4 vectors.

        This different prediction affects only 16x16 vectors of MBs with
        transparent blocks.

        In the current version, we choose for the 16x16 mode the first
        non-transparent block in the surrounding MBs
    */

    switch (block)
    {
        case 0:
            vec1 = 2 ;
            yin1 = y  ;
            xin1 = x - 1;
            vec2 = 3 ;
            yin2 = y - 1;
            xin2 = x;
            vec3 = 3 ;
            yin3 = y - 1;
            xin3 = x + 1;
            break;

        case 1:
            vec1 = 2 ;
            yin1 = y  ;
            xin1 = x - 1;
            vec2 = 3 ;
            yin2 = y - 1;
            xin2 = x;
            vec3 = 3 ;
            yin3 = y - 1;
            xin3 = x + 1;
            break;

        case 2:
            vec1 = 1 ;
            yin1 = y  ;
            xin1 = x;
            vec2 = 4 ;
            yin2 = y - 1;
            xin2 = x;
            vec3 = 3 ;
            yin3 = y - 1;
            xin3 = x + 1;
            break;

        case 3:
            vec1 = 4 ;
            yin1 = y  ;
            xin1 = x - 1;
            vec2 = 1 ;
            yin2 = y  ;
            xin2 = x;
            vec3 = 2 ;
            yin3 = y  ;
            xin3 = x;
            break;

        default: /* case 4 */
            vec1 = 3 ;
            yin1 = y  ;
            xin1 = x;
            vec2 = 1 ;
            yin2 = y  ;
            xin2 = x;
            vec3 = 2 ;
            yin3 = y  ;
            xin3 = x;
            break;
    }

    if (block == 0)
    {
        /* according to the motion encoding, we must choose a first non-transparent
        block in the surrounding MBs (16-mode)
            */

        if (x > 0 && slice_nb[mbnum] == slice_nb[mbnum-1])
            rule1 = 0;
        else
            rule1 = 1;

        if (y > 0 && slice_nb[mbnum] == slice_nb[mbnum-nMBPerRow])
            rule2 = 0;
        else
            rule2 = 1;

        if ((x != nMBPerRow - 1) && (y > 0) && slice_nb[mbnum] == slice_nb[mbnum+1-nMBPerRow])
            rule3 = 0;
        else
            rule3 = 1;
    }
    else
    {
        /* check borders for single blocks (advanced mode) */
        /* rule 1 */
        if (((block == 1 || block == 3) &&
                (x == 0 || slice_nb[mbnum] != slice_nb[mbnum-1])))
            rule1 = 1;
        else
            rule1 = 0;

        /* rule 2 */
        if (((block == 1 || block == 2) &&
                (y == 0 || slice_nb[mbnum] != slice_nb[mbnum-nMBPerRow])))
            rule2 = 1;
        else
            rule2 = 0;

        /* rule 3 */
        if (((block == 1 || block == 2) &&
                (x == nMBPerRow - 1 || y == 0 || slice_nb[mbnum] != slice_nb[mbnum+1-nMBPerRow])))
            rule3 = 1;
        else
            rule3 = 0;
    }

    if (rule1)
    {
        p1x = p1y = 0;
    }
    else
    {

        p1x = motdata[yin1*nMBPerRow+xin1][vec1].x;
        p1y = motdata[yin1*nMBPerRow+xin1][vec1].y;
        //p1x = motxdata[xin1*2+(vec1&0x1) + (yin1*2+(vec1>>1))*xB];
        //p1y = motydata[xin1*2+(vec1&0x1) + (yin1*2+(vec1>>1))*xB];
    }

    if (rule2)
    {
        p2x = p2y = 0;
    }
    else
    {
        p2x = motdata[yin2*nMBPerRow+xin2][vec2].x;
        p2y = motdata[yin2*nMBPerRow+xin2][vec2].y;
        //p2x = motxdata[xin2*2+(vec2&0x1) + (yin2*2+(vec2>>1))*xB];
        //p2y = motydata[xin2*2+(vec2&0x1) + (yin2*2+(vec2>>1))*xB];
    }

    if (rule3)
    {
        p3x = p3y = 0;
    }
    else
    {
        p3x = motdata[yin3*nMBPerRow+xin3][vec3].x;
        p3y = motdata[yin3*nMBPerRow+xin3][vec3].y;
        //p3x = motxdata[xin3*2+ (vec3&0x1) + (yin3*2+(vec3>>1))*xB];
        //p3y = motydata[xin3*2+ (vec3&0x1) + (yin3*2+(vec3>>1))*xB];
    }

    if (rule1 && rule2 && rule3)
    {
        /* all MBs are outside the VOP */
        *mvx = *mvy = 0;
    }
    else if (rule1 + rule2 + rule3 == 2)
    {
        /* two of three are zero */
        *mvx = (p1x + p2x + p3x);
        *mvy = (p1y + p2y + p3y);
    }
    else
    {
        *mvx = ((p1x + p2x + p3x - PV_MAX(p1x, PV_MAX(p2x, p3x)) - PV_MIN(p1x, PV_MIN(p2x, p3x))));
        *mvy = ((p1y + p2y + p3y - PV_MAX(p1y, PV_MAX(p2y, p3y)) - PV_MIN(p1y, PV_MIN(p2y, p3y))));
    }

    return;
}


Void WriteMVcomponent(Int f_code, Int dmv, BitstreamEncVideo *bs)
{
    Int residual, vlc_code_mag, bits, entry;

    ScaleMVD(f_code, dmv, &residual, &vlc_code_mag);

    if (vlc_code_mag < 0)
        entry = vlc_code_mag + 65;
    else
        entry = vlc_code_mag;

    bits = PutMV(entry, bs);

    if ((f_code != 1) && (vlc_code_mag != 0))
    {
        BitstreamPutBits(bs, f_code - 1, residual);
        bits += f_code - 1;
    }
    return;
}


Void
ScaleMVD(
    Int  f_code,       /* <-- MV range in 1/2 units: 1=32,2=64,...,7=2048     */
    Int  diff_vector,  /* <-- MV Difference commponent in 1/2 units           */
    Int  *residual,    /* --> value to be FLC coded                           */
    Int  *vlc_code_mag /* --> value to be VLC coded                           */
)
{
    Int   range;
    Int   scale_factor;
    Int   r_size;
    Int   low;
    Int   high;
    Int   aux;

    r_size = f_code - 1;
    scale_factor = 1 << r_size;
    range = 32 * scale_factor;
    low   = -range;
    high  =  range - 1;

    if (diff_vector < low)
        diff_vector += 2 * range;
    else if (diff_vector > high)
        diff_vector -= 2 * range;

    if (diff_vector == 0)
    {
        *vlc_code_mag = 0;
        *residual = 0;
    }
    else if (scale_factor == 1)
    {
        *vlc_code_mag = diff_vector;
        *residual = 0;
    }
    else
    {
        aux = PV_ABS(diff_vector) + scale_factor - 1;
        *vlc_code_mag = aux >> r_size;

        if (diff_vector < 0)
            *vlc_code_mag = -*vlc_code_mag;
        *residual = aux & (scale_factor - 1);
    }
}
