/* ------------------------------------------------------------------
 * 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.
 * -------------------------------------------------------------------
 */

#include <string.h>

#include "avclib_common.h"

#define MAX_QP 51
#define MB_BLOCK_SIZE 16

// NOTE: these 3 tables are for funtion GetStrength() only
const static int ININT_STRENGTH[4] = {0x04040404, 0x03030303, 0x03030303, 0x03030303};


// NOTE: these 3 tables are for funtion EdgeLoop() only
// NOTE: to change the tables below for instance when the QP doubling is changed from 6 to 8 values

const static int ALPHA_TABLE[52]  = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 5, 6,  7, 8, 9, 10, 12, 13, 15, 17,  20, 22, 25, 28, 32, 36, 40, 45,  50, 56, 63, 71, 80, 90, 101, 113,  127, 144, 162, 182, 203, 226, 255, 255} ;
const static int BETA_TABLE[52]   = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 3,  3, 3, 3, 4, 4, 4, 6, 6,   7, 7, 8, 8, 9, 9, 10, 10,  11, 11, 12, 12, 13, 13, 14, 14,   15, 15, 16, 16, 17, 17, 18, 18} ;
const static int CLIP_TAB[52][5]  =
{
    { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0},
    { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0},
    { 0, 0, 0, 0, 0}, { 0, 0, 0, 1, 1}, { 0, 0, 0, 1, 1}, { 0, 0, 0, 1, 1}, { 0, 0, 0, 1, 1}, { 0, 0, 1, 1, 1}, { 0, 0, 1, 1, 1}, { 0, 1, 1, 1, 1},
    { 0, 1, 1, 1, 1}, { 0, 1, 1, 1, 1}, { 0, 1, 1, 1, 1}, { 0, 1, 1, 2, 2}, { 0, 1, 1, 2, 2}, { 0, 1, 1, 2, 2}, { 0, 1, 1, 2, 2}, { 0, 1, 2, 3, 3},
    { 0, 1, 2, 3, 3}, { 0, 2, 2, 3, 3}, { 0, 2, 2, 4, 4}, { 0, 2, 3, 4, 4}, { 0, 2, 3, 4, 4}, { 0, 3, 3, 5, 5}, { 0, 3, 4, 6, 6}, { 0, 3, 4, 6, 6},
    { 0, 4, 5, 7, 7}, { 0, 4, 5, 8, 8}, { 0, 4, 6, 9, 9}, { 0, 5, 7, 10, 10}, { 0, 6, 8, 11, 11}, { 0, 6, 8, 13, 13}, { 0, 7, 10, 14, 14}, { 0, 8, 11, 16, 16},
    { 0, 9, 12, 18, 18}, { 0, 10, 13, 20, 20}, { 0, 11, 15, 23, 23}, { 0, 13, 17, 25, 25}
};

// NOTE: this table is only QP clipping, index = QP + video->FilterOffsetA/B, clipped to [0, 51]
//       video->FilterOffsetA/B is in {-12, 12]
const static int QP_CLIP_TAB[76] =
{
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,              // [-12, 0]
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
    13, 14, 15, 16, 17, 18, 19, 20, 21,
    22, 23, 24, 25, 26, 27, 28, 29, 30,
    31, 32, 33, 34, 35, 36, 37, 38, 39,
    40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // [1, 51]
    51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51      // [52,63]
};

static void DeblockMb(AVCCommonObj *video, int mb_x, int mb_y, uint8 *SrcY, uint8 *SrcU, uint8 *SrcV);
//static void GetStrength(AVCCommonObj *video, uint8 *Strength, AVCMacroblock* MbP, AVCMacroblock* MbQ, int dir, int edge);
static void GetStrength_Edge0(uint8 *Strength, AVCMacroblock* MbP, AVCMacroblock* MbQ, int dir);
static void GetStrength_VerticalEdges(uint8 *Strength, AVCMacroblock* MbQ);
static void GetStrength_HorizontalEdges(uint8 Strength[12], AVCMacroblock* MbQ);
static void EdgeLoop_Luma_vertical(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch);
static void EdgeLoop_Luma_horizontal(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch);
static void EdgeLoop_Chroma_vertical(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch);
static void EdgeLoop_Chroma_horizontal(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch);

/*
 *****************************************************************************************
 * \brief Filter all macroblocks in order of increasing macroblock address.
 *****************************************************************************************
*/

OSCL_EXPORT_REF AVCStatus DeblockPicture(AVCCommonObj *video)
{
    uint   i, j;
    int   pitch = video->currPic->pitch, pitch_c, width;
    uint8 *SrcY, *SrcU, *SrcV;

    SrcY = video->currPic->Sl;      // pointers to source
    SrcU = video->currPic->Scb;
    SrcV = video->currPic->Scr;
    pitch_c = pitch >> 1;
    width = video->currPic->width;

    for (i = 0; i < video->PicHeightInMbs; i++)
    {
        for (j = 0; j < video->PicWidthInMbs; j++)
        {
            DeblockMb(video, j, i, SrcY, SrcU, SrcV);
            // update SrcY, SrcU, SrcV
            SrcY += MB_BLOCK_SIZE;
            SrcU += (MB_BLOCK_SIZE >> 1);
            SrcV += (MB_BLOCK_SIZE >> 1);
        }

        SrcY += ((pitch << 4) - width);
        SrcU += ((pitch_c << 3) - (width >> 1));
        SrcV += ((pitch_c << 3) - (width >> 1));
    }

    return AVC_SUCCESS;
}

#ifdef MB_BASED_DEBLOCK
/*
 *****************************************************************************************
 * \brief Filter one macroblocks in a fast macroblock memory and copy it to frame
 *****************************************************************************************
*/
void MBInLoopDeblock(AVCCommonObj *video)
{
    AVCPictureData *currPic = video->currPic;
#ifdef USE_PRED_BLOCK
    uint8 *predCb, *predCr, *pred_block;
    int i, j, dst_width, dst_height, dst_widthc, dst_heightc;
#endif
    int pitch = currPic->pitch;
    int x_pos = video->mb_x;
    int y_pos = video->mb_y;
    uint8 *curL, *curCb, *curCr;
    int offset;

    offset = (y_pos << 4) * pitch;

    curL = currPic->Sl + offset + (x_pos << 4);

    offset >>= 2;
    offset += (x_pos << 3);

    curCb = currPic->Scb + offset;
    curCr = currPic->Scr + offset;

#ifdef USE_PRED_BLOCK
    pred_block = video->pred;

    /* 1. copy neighboring pixels from frame to the video->pred_block */
    if (y_pos) /* not the 0th row */
    {
        /* copy to the top 4 lines of the macroblock */
        curL -= (pitch << 2); /* go back 4 lines */

        memcpy(pred_block + 4, curL, 16);
        curL += pitch;
        memcpy(pred_block + 24, curL, 16);
        curL += pitch;
        memcpy(pred_block + 44, curL, 16);
        curL += pitch;
        memcpy(pred_block + 64, curL, 16);
        curL += pitch;

        curCb -= (pitch << 1); /* go back 4 lines chroma */
        curCr -= (pitch << 1);

        pred_block += 400;

        memcpy(pred_block + 4, curCb, 8);
        curCb += (pitch >> 1);
        memcpy(pred_block + 16, curCb, 8);
        curCb += (pitch >> 1);
        memcpy(pred_block + 28, curCb, 8);
        curCb += (pitch >> 1);
        memcpy(pred_block + 40, curCb, 8);
        curCb += (pitch >> 1);

        pred_block += 144;
        memcpy(pred_block + 4, curCr, 8);
        curCr += (pitch >> 1);
        memcpy(pred_block + 16, curCr, 8);
        curCr += (pitch >> 1);
        memcpy(pred_block + 28, curCr, 8);
        curCr += (pitch >> 1);
        memcpy(pred_block + 40, curCr, 8);
        curCr += (pitch >> 1);

        pred_block = video->pred;
    }

    /* 2. perform deblocking. */
    DeblockMb(video, x_pos, y_pos, pred_block + 84, pred_block + 452, pred_block + 596);

    /* 3. copy it back to the frame and update pred_block */
    predCb = pred_block + 400;
    predCr = predCb + 144;

    /* find the range of the block inside pred_block to be copied back */
    if (y_pos)  /* the first row */
    {
        curL -= (pitch << 2);
        curCb -= (pitch << 1);
        curCr -= (pitch << 1);

        dst_height = 20;
        dst_heightc = 12;
    }
    else
    {
        pred_block += 80;
        predCb += 48;
        predCr += 48;
        dst_height = 16;
        dst_heightc = 8;
    }

    if (x_pos) /* find the width */
    {
        curL -= 4;
        curCb -= 4;
        curCr -= 4;
        if (x_pos == (int)(video->PicWidthInMbs - 1))
        {
            dst_width = 20;
            dst_widthc = 12;
        }
        else
        {
            dst_width = 16;
            dst_widthc = 8;
        }
    }
    else
    {
        pred_block += 4;
        predCb += 4;
        predCr += 4;
        dst_width = 12;
        dst_widthc = 4;
    }

    /* perform copy */
    for (j = 0; j < dst_height; j++)
    {
        memcpy(curL, pred_block, dst_width);
        curL += pitch;
        pred_block += 20;
    }
    for (j = 0; j < dst_heightc; j++)
    {
        memcpy(curCb, predCb, dst_widthc);
        memcpy(curCr, predCr, dst_widthc);
        curCb += (pitch >> 1);
        curCr += (pitch >> 1);
        predCb += 12;
        predCr += 12;
    }

    if (x_pos != (int)(video->PicWidthInMbs - 1)) /* now copy from the right-most 4 columns to the left-most 4 columns */
    {
        pred_block = video->pred;
        for (i = 0; i < 20; i += 4)
        {
            *((uint32*)pred_block) = *((uint32*)(pred_block + 16));
            pred_block += 20;
            *((uint32*)pred_block) = *((uint32*)(pred_block + 16));
            pred_block += 20;
            *((uint32*)pred_block) = *((uint32*)(pred_block + 16));
            pred_block += 20;
            *((uint32*)pred_block) = *((uint32*)(pred_block + 16));
            pred_block += 20;
        }

        for (i = 0; i < 24; i += 4)
        {
            *((uint32*)pred_block) = *((uint32*)(pred_block + 8));
            pred_block += 12;
            *((uint32*)pred_block) = *((uint32*)(pred_block + 8));
            pred_block += 12;
            *((uint32*)pred_block) = *((uint32*)(pred_block + 8));
            pred_block += 12;
            *((uint32*)pred_block) = *((uint32*)(pred_block + 8));
            pred_block += 12;
        }

    }
#else
    DeblockMb(video, x_pos, y_pos, curL, curCb, curCr);
#endif

    return ;
}
#endif

/*
 *****************************************************************************************
 * \brief Deblocking filter for one macroblock.
 *****************************************************************************************
 */

void DeblockMb(AVCCommonObj *video, int mb_x, int mb_y, uint8 *SrcY, uint8 *SrcU, uint8 *SrcV)
{
    AVCMacroblock *MbP, *MbQ;
    int     edge, QP, QPC;
    int     filterLeftMbEdgeFlag = (mb_x != 0);
    int     filterTopMbEdgeFlag  = (mb_y != 0);
    int     pitch = video->currPic->pitch;
    int     indexA, indexB;
    int     *tmp;
    int     Alpha, Beta, Alpha_c, Beta_c;
    int     mbNum = mb_y * video->PicWidthInMbs + mb_x;
    int     *clipTable, *clipTable_c, *qp_clip_tab;
    uint8   Strength[16];
    void*     str;

    MbQ = &(video->mblock[mbNum]);      // current Mb


    // If filter is disabled, return
    if (video->sliceHdr->disable_deblocking_filter_idc == 1) return;

    if (video->sliceHdr->disable_deblocking_filter_idc == 2)
    {
        // don't filter at slice boundaries
        filterLeftMbEdgeFlag = mb_is_available(video->mblock, video->PicSizeInMbs, mbNum - 1, mbNum);
        filterTopMbEdgeFlag  = mb_is_available(video->mblock, video->PicSizeInMbs, mbNum - video->PicWidthInMbs, mbNum);
    }

    /* NOTE: edge=0 and edge=1~3 are separate cases because of the difference of MbP, index A and indexB calculation */
    /*       for edge = 1~3, MbP, indexA and indexB remain the same, and thus there is no need to re-calculate them for each edge */

    qp_clip_tab = (int *)QP_CLIP_TAB + 12;

    /* 1.VERTICAL EDGE + MB BOUNDARY (edge = 0) */
    if (filterLeftMbEdgeFlag)
    {
        MbP = MbQ - 1;
        //GetStrength(video, Strength, MbP, MbQ, 0, 0); // Strength for 4 blks in 1 stripe, 0 => vertical edge
        GetStrength_Edge0(Strength, MbP, MbQ, 0);

        str = (void*)Strength; //de-ref type-punned pointer fix
        if (*((uint32*)str))    // only if one of the 4 Strength bytes is != 0
        {
            QP = (MbP->QPy + MbQ->QPy + 1) >> 1; // Average QP of the two blocks;
            indexA = QP + video->FilterOffsetA;
            indexB = QP + video->FilterOffsetB;
            indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA)
            indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB)

            Alpha  = ALPHA_TABLE[indexA];
            Beta = BETA_TABLE[indexB];
            clipTable = (int *) CLIP_TAB[indexA];

            if (Alpha > 0 && Beta > 0)
#ifdef USE_PRED_BLOCK
                EdgeLoop_Luma_vertical(SrcY, Strength,  Alpha, Beta, clipTable, 20);
#else
                EdgeLoop_Luma_vertical(SrcY, Strength,  Alpha, Beta, clipTable, pitch);
#endif

            QPC = (MbP->QPc + MbQ->QPc + 1) >> 1;
            indexA = QPC + video->FilterOffsetA;
            indexB = QPC + video->FilterOffsetB;
            indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA)
            indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB)

            Alpha  = ALPHA_TABLE[indexA];
            Beta = BETA_TABLE[indexB];
            clipTable = (int *) CLIP_TAB[indexA];
            if (Alpha > 0 && Beta > 0)
            {
#ifdef USE_PRED_BLOCK
                EdgeLoop_Chroma_vertical(SrcU, Strength, Alpha, Beta, clipTable, 12);
                EdgeLoop_Chroma_vertical(SrcV, Strength, Alpha, Beta, clipTable, 12);
#else
                EdgeLoop_Chroma_vertical(SrcU, Strength, Alpha, Beta, clipTable, pitch >> 1);
                EdgeLoop_Chroma_vertical(SrcV, Strength, Alpha, Beta, clipTable, pitch >> 1);
#endif
            }
        }

    } /* end of: if(filterLeftMbEdgeFlag) */

    /* 2.VERTICAL EDGE (no boundary), the edges are all inside a MB */
    /* First calculate the necesary parameters all at once, outside the loop */
    MbP = MbQ;

    indexA = MbQ->QPy + video->FilterOffsetA;
    indexB = MbQ->QPy + video->FilterOffsetB;
    //  index
    indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA)
    indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB)

    Alpha = ALPHA_TABLE[indexA];
    Beta = BETA_TABLE[indexB];
    clipTable = (int *)CLIP_TAB[indexA];

    /* Save Alpha,  Beta and clipTable for future use, with the obselete variables filterLeftMbEdgeFlag, mbNum amd tmp */
    filterLeftMbEdgeFlag = Alpha;
    mbNum = Beta;
    tmp = clipTable;

    indexA = MbQ->QPc + video->FilterOffsetA;
    indexB = MbQ->QPc + video->FilterOffsetB;
    indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA)
    indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB)

    Alpha_c  = ALPHA_TABLE[indexA];
    Beta_c = BETA_TABLE[indexB];
    clipTable_c = (int *)CLIP_TAB[indexA];

    GetStrength_VerticalEdges(Strength + 4, MbQ); // Strength for 4 blks in 1 stripe, 0 => vertical edge

    for (edge = 1; edge < 4; edge++)  // 4 vertical strips of 16 pel
    {
        //GetStrength_VerticalEdges(video, Strength, MbP, MbQ, 0, edge); // Strength for 4 blks in 1 stripe, 0 => vertical edge
        if (*((int*)(Strength + (edge << 2))))   // only if one of the 4 Strength bytes is != 0
        {
            if (Alpha > 0 && Beta > 0)
#ifdef USE_PRED_BLOCK
                EdgeLoop_Luma_vertical(SrcY + (edge << 2), Strength + (edge << 2),  Alpha, Beta, clipTable, 20);
#else
                EdgeLoop_Luma_vertical(SrcY + (edge << 2), Strength + (edge << 2),  Alpha, Beta, clipTable, pitch);
#endif

            if (!(edge & 1) && Alpha_c > 0 && Beta_c > 0)
            {
#ifdef USE_PRED_BLOCK
                EdgeLoop_Chroma_vertical(SrcU + (edge << 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, 12);
                EdgeLoop_Chroma_vertical(SrcV + (edge << 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, 12);
#else
                EdgeLoop_Chroma_vertical(SrcU + (edge << 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, pitch >> 1);
                EdgeLoop_Chroma_vertical(SrcV + (edge << 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, pitch >> 1);
#endif
            }
        }

    } //end edge



    /* 3.HORIZONTAL EDGE + MB BOUNDARY (edge = 0) */
    if (filterTopMbEdgeFlag)
    {
        MbP = MbQ - video->PicWidthInMbs;
        //GetStrength(video, Strength, MbP, MbQ, 1, 0); // Strength for 4 blks in 1 stripe, 0 => vertical edge
        GetStrength_Edge0(Strength, MbP, MbQ, 1);
        str = (void*)Strength; //de-ref type-punned pointer fix
        if (*((uint32*)str))    // only if one of the 4 Strength bytes is != 0
        {
            QP = (MbP->QPy + MbQ->QPy + 1) >> 1; // Average QP of the two blocks;
            indexA = QP + video->FilterOffsetA;
            indexB = QP + video->FilterOffsetB;
            indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA)
            indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB)

            Alpha  = ALPHA_TABLE[indexA];
            Beta = BETA_TABLE[indexB];
            clipTable = (int *)CLIP_TAB[indexA];

            if (Alpha > 0 && Beta > 0)
            {
#ifdef USE_PRED_BLOCK
                EdgeLoop_Luma_horizontal(SrcY, Strength,  Alpha, Beta, clipTable, 20);
#else
                EdgeLoop_Luma_horizontal(SrcY, Strength,  Alpha, Beta, clipTable, pitch);
#endif
            }

            QPC = (MbP->QPc + MbQ->QPc + 1) >> 1;
            indexA = QPC + video->FilterOffsetA;
            indexB = QPC + video->FilterOffsetB;
            indexA = qp_clip_tab[indexA]; // IClip(0, MAX_QP, QP+video->FilterOffsetA)
            indexB = qp_clip_tab[indexB]; // IClip(0, MAX_QP, QP+video->FilterOffsetB)

            Alpha  = ALPHA_TABLE[indexA];
            Beta = BETA_TABLE[indexB];
            clipTable = (int *)CLIP_TAB[indexA];
            if (Alpha > 0 && Beta > 0)
            {
#ifdef USE_PRED_BLOCK
                EdgeLoop_Chroma_horizontal(SrcU, Strength, Alpha, Beta, clipTable, 12);
                EdgeLoop_Chroma_horizontal(SrcV, Strength, Alpha, Beta, clipTable, 12);
#else
                EdgeLoop_Chroma_horizontal(SrcU, Strength, Alpha, Beta, clipTable, pitch >> 1);
                EdgeLoop_Chroma_horizontal(SrcV, Strength, Alpha, Beta, clipTable, pitch >> 1);
#endif
            }
        }

    } /* end of: if(filterTopMbEdgeFlag) */


    /* 4.HORIZONTAL EDGE (no boundary), the edges are inside a MB */
    MbP = MbQ;

    /* Recover Alpha,  Beta and clipTable for edge!=0 with the variables filterLeftMbEdgeFlag, mbNum and tmp */
    /* Note that Alpha_c, Beta_c and clipTable_c for chroma is already calculated */
    Alpha = filterLeftMbEdgeFlag;
    Beta = mbNum;
    clipTable = tmp;

    GetStrength_HorizontalEdges(Strength + 4, MbQ); // Strength for 4 blks in 1 stripe, 0 => vertical edge

    for (edge = 1; edge < 4; edge++)  // 4 horicontal strips of 16 pel
    {
        //GetStrength(video, Strength, MbP, MbQ, 1, edge); // Strength for 4 blks in 1 stripe   1 => horizontal edge
        if (*((int*)(Strength + (edge << 2)))) // only if one of the 4 Strength bytes is != 0
        {
            if (Alpha > 0 && Beta > 0)
            {
#ifdef USE_PRED_BLOCK
                EdgeLoop_Luma_horizontal(SrcY + (edge << 2)*20, Strength + (edge << 2),  Alpha, Beta, clipTable, 20);
#else
                EdgeLoop_Luma_horizontal(SrcY + (edge << 2)*pitch, Strength + (edge << 2),  Alpha, Beta, clipTable, pitch);
#endif
            }

            if (!(edge & 1) && Alpha_c > 0 && Beta_c > 0)
            {
#ifdef USE_PRED_BLOCK
                EdgeLoop_Chroma_horizontal(SrcU + (edge << 1)*12, Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, 12);
                EdgeLoop_Chroma_horizontal(SrcV + (edge << 1)*12, Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, 12);
#else
                EdgeLoop_Chroma_horizontal(SrcU + (edge << 1)*(pitch >> 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, pitch >> 1);
                EdgeLoop_Chroma_horizontal(SrcV + (edge << 1)*(pitch >> 1), Strength + (edge << 2), Alpha_c, Beta_c, clipTable_c, pitch >> 1);
#endif
            }
        }

    } //end edge

    return;
}

/*
 *****************************************************************************************************
 * \brief   returns a buffer of 4 Strength values for one stripe in a mb (for different Frame types)
 *****************************************************************************************************
*/

void GetStrength_Edge0(uint8 *Strength, AVCMacroblock* MbP, AVCMacroblock* MbQ, int dir)
{
    int tmp;
    int16 *ptrQ, *ptrP;
    void* vptr;
    uint8 *pStrength;
    void* refIdx;

    if (MbP->mbMode == AVC_I4 || MbP->mbMode == AVC_I16 ||
            MbQ->mbMode == AVC_I4 || MbQ->mbMode == AVC_I16)
    {

        *((int*)Strength) = ININT_STRENGTH[0];      // Start with Strength=3. or Strength=4 for Mb-edge

    }
    else // if not intra or SP-frame
    {
        *((int*)Strength) = 0;

        if (dir == 0)  // Vertical Edge 0
        {

            //1. Check the ref_frame_id
            refIdx = (void*) MbQ->RefIdx; //de-ref type-punned pointer fix
            ptrQ = (int16*)refIdx;
            refIdx = (void*)MbP->RefIdx; //de-ref type-punned pointer fix
            ptrP = (int16*)refIdx;
            pStrength = Strength;
            if (ptrQ[0] != ptrP[1]) pStrength[0] = 1;
            if (ptrQ[2] != ptrP[3]) pStrength[2] = 1;
            pStrength[1] = pStrength[0];
            pStrength[3] = pStrength[2];

            //2. Check the non-zero coeff blocks (4x4)
            if (MbQ->nz_coeff[0] != 0 || MbP->nz_coeff[3] != 0) pStrength[0] = 2;
            if (MbQ->nz_coeff[4] != 0 || MbP->nz_coeff[7] != 0) pStrength[1] = 2;
            if (MbQ->nz_coeff[8] != 0 || MbP->nz_coeff[11] != 0) pStrength[2] = 2;
            if (MbQ->nz_coeff[12] != 0 || MbP->nz_coeff[15] != 0) pStrength[3] = 2;

            //3. Only need to check the mv difference
            vptr = (void*)MbQ->mvL0;  // for deref type-punned pointer
            ptrQ = (int16*)vptr;
            ptrP = (int16*)(MbP->mvL0 + 3); // points to 4x4 block #3 (the 4th column)

            // 1st blk
            if (*pStrength == 0)
            {
                // check |mv difference| >= 4
                tmp = *ptrQ++ - *ptrP++;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *ptrQ-- - *ptrP--;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }

            pStrength++;
            ptrQ += 8;
            ptrP += 8;

            // 2nd blk
            if (*pStrength == 0)
            {
                // check |mv difference| >= 4
                tmp = *ptrQ++ - *ptrP++;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *ptrQ-- - *ptrP--;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }

            pStrength++;
            ptrQ += 8;
            ptrP += 8;

            // 3rd blk
            if (*pStrength == 0)
            {
                // check |mv difference| >= 4
                tmp = *ptrQ++ - *ptrP++;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *ptrQ-- - *ptrP--;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }

            pStrength++;
            ptrQ += 8;
            ptrP += 8;

            // 4th blk
            if (*pStrength == 0)
            {
                // check |mv difference| >= 4
                tmp = *ptrQ++ - *ptrP++;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *ptrQ-- - *ptrP--;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }
        }
        else   // Horizontal Edge 0
        {

            //1. Check the ref_frame_id
            refIdx = (void*)MbQ->RefIdx;  //de-ref type-punned pointer
            ptrQ = (int16*)refIdx;
            refIdx = (void*)MbP->RefIdx;  //de-ref type-punned pointer
            ptrP = (int16*)refIdx;
            pStrength = Strength;
            if (ptrQ[0] != ptrP[2]) pStrength[0] = 1;
            if (ptrQ[1] != ptrP[3]) pStrength[2] = 1;
            pStrength[1] = pStrength[0];
            pStrength[3] = pStrength[2];

            //2. Check the non-zero coeff blocks (4x4)
            if (MbQ->nz_coeff[0] != 0 || MbP->nz_coeff[12] != 0) pStrength[0] = 2;
            if (MbQ->nz_coeff[1] != 0 || MbP->nz_coeff[13] != 0) pStrength[1] = 2;
            if (MbQ->nz_coeff[2] != 0 || MbP->nz_coeff[14] != 0) pStrength[2] = 2;
            if (MbQ->nz_coeff[3] != 0 || MbP->nz_coeff[15] != 0) pStrength[3] = 2;

            //3. Only need to check the mv difference
            vptr = (void*)MbQ->mvL0;
            ptrQ = (int16*)vptr;
            ptrP = (int16*)(MbP->mvL0 + 12); // points to 4x4 block #12 (the 4th row)

            // 1st blk
            if (*pStrength == 0)
            {
                // check |mv difference| >= 4
                tmp = *ptrQ++ - *ptrP++;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *ptrQ-- - *ptrP--;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }

            pStrength++;
            ptrQ += 2;
            ptrP += 2;

            // 2nd blk
            if (*pStrength  == 0)
            {
                // check |mv difference| >= 4
                tmp = *ptrQ++ - *ptrP++;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *ptrQ-- - *ptrP--;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }

            pStrength++;
            ptrQ += 2;
            ptrP += 2;

            // 3rd blk
            if (*pStrength  == 0)
            {
                // check |mv difference| >= 4
                tmp = *ptrQ++ - *ptrP++;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *ptrQ-- - *ptrP--;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }

            pStrength++;
            ptrQ += 2;
            ptrP += 2;

            // 4th blk
            if (*pStrength  == 0)
            {
                // check |mv difference| >= 4
                tmp = *ptrQ++ - *ptrP++;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *ptrQ-- - *ptrP--;
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }

        } /* end of: else if(dir == 0) */

    } /* end of: if( !(MbP->mbMode == AVC_I4 ...) */
}


void GetStrength_VerticalEdges(uint8 *Strength, AVCMacroblock* MbQ)
{
    int     idx, tmp;
    int16   *ptr, *pmvx, *pmvy;
    uint8   *pnz;
    uint8   *pStrength, *pStr;
    void* refIdx;

    if (MbQ->mbMode == AVC_I4 || MbQ->mbMode == AVC_I16)
    {
        *((int*)Strength)     = ININT_STRENGTH[1];      // Start with Strength=3. or Strength=4 for Mb-edge
        *((int*)(Strength + 4)) = ININT_STRENGTH[2];
        *((int*)(Strength + 8)) = ININT_STRENGTH[3];
    }
    else   // Not intra or SP-frame
    {

        *((int*)Strength)     = 0; // for non-intra MB, strength = 0, 1 or 2.
        *((int*)(Strength + 4)) = 0;
        *((int*)(Strength + 8)) = 0;

        //1. Check the ref_frame_id
        refIdx = (void*)MbQ->RefIdx;  //de-ref type-punned pointer fix
        ptr = (int16*)refIdx;
        pStrength = Strength;
        if (ptr[0] != ptr[1]) pStrength[4] = 1;
        if (ptr[2] != ptr[3]) pStrength[6] = 1;
        pStrength[5] = pStrength[4];
        pStrength[7] = pStrength[6];

        //2. Check the nz_coeff block and mv difference
        pmvx = (int16*)(MbQ->mvL0 + 1); // points to 4x4 block #1,not #0
        pmvy = pmvx + 1;
        for (idx = 0; idx < 4; idx += 2) // unroll the loop, make 4 iterations to 2
        {
            // first/third row : 1,2,3 or 9,10,12
            // Strength = 2 for a whole row
            pnz = MbQ->nz_coeff + (idx << 2);
            if (*pnz++ != 0) *pStrength = 2;
            if (*pnz++ != 0)
            {
                *pStrength = 2;
                *(pStrength + 4) = 2;
            }
            if (*pnz++ != 0)
            {
                *(pStrength + 4) = 2;
                *(pStrength + 8) = 2;
            }
            if (*pnz != 0) *(pStrength + 8) = 2;

            // Then Strength = 1
            if (*pStrength == 0)
            {
                //within the same 8x8 block, no need to check the reference id
                //only need to check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *pmvy - *(pmvy - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }

            pmvx += 2;
            pmvy += 2;
            pStr = pStrength + 4;

            if (*pStr == 0)
            {
                //check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            pmvx += 2;
            pmvy += 2;
            pStr = pStrength + 8;

            if (*pStr == 0)
            {
                //within the same 8x8 block, no need to check the reference id
                //only need to check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            // Second/fourth row: 5,6,7 or 14,15,16
            // Strength = 2 for a whole row
            pnz = MbQ->nz_coeff + ((idx + 1) << 2);
            if (*pnz++ != 0) *(pStrength + 1) = 2;
            if (*pnz++ != 0)
            {
                *(pStrength + 1) = 2;
                *(pStrength + 5) = 2;
            }
            if (*pnz++ != 0)
            {
                *(pStrength + 5) = 2;
                *(pStrength + 9) = 2;
            }
            if (*pnz != 0) *(pStrength + 9) = 2;

            // Then Strength = 1
            pmvx += 4;
            pmvy += 4;
            pStr = pStrength + 1;
            if (*pStr == 0)
            {
                //within the same 8x8 block, no need to check the reference id
                //only need to check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            pmvx += 2;
            pmvy += 2;
            pStr = pStrength + 5;

            if (*pStr == 0)
            {
                //check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            pmvx += 2;
            pmvy += 2;
            pStr = pStrength + 9;

            if (*pStr == 0)
            {
                //within the same 8x8 block, no need to check the reference id
                //only need to check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 2);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            // update some variables for the next two rows
            pmvx += 4;
            pmvy += 4;
            pStrength += 2;

        } /* end of: for(idx=0; idx<2; idx++) */

    } /* end of: else if( MbQ->mbMode == AVC_I4 ...) */
}


void GetStrength_HorizontalEdges(uint8 Strength[12], AVCMacroblock* MbQ)
{
    int     idx, tmp;
    int16   *ptr, *pmvx, *pmvy;
    uint8   *pStrength, *pStr;
    void* refIdx;

    if (MbQ->mbMode == AVC_I4 || MbQ->mbMode == AVC_I16)
    {
        *((int*)Strength)     = ININT_STRENGTH[1];      // Start with Strength=3. or Strength=4 for Mb-edge
        *((int*)(Strength + 4)) = ININT_STRENGTH[2];
        *((int*)(Strength + 8)) = ININT_STRENGTH[3];
    }
    else   // Not intra or SP-frame
    {

        *((int*)Strength)     = 0; // for non-intra MB, strength = 0, 1 or 2.
        *((int*)(Strength + 4)) = 0; // for non-intra MB, strength = 0, 1 or 2.
        *((int*)(Strength + 8)) = 0; // for non-intra MB, strength = 0, 1 or 2.


        //1. Check the ref_frame_id
        refIdx = (void*) MbQ->RefIdx; // de-ref type-punned fix
        ptr = (int16*) refIdx;
        pStrength = Strength;
        if (ptr[0] != ptr[2]) pStrength[4] = 1;
        if (ptr[1] != ptr[3]) pStrength[6] = 1;
        pStrength[5] = pStrength[4];
        pStrength[7] = pStrength[6];

        //2. Check the nz_coeff block and mv difference
        pmvx = (int16*)(MbQ->mvL0 + 4); // points to 4x4 block #4,not #0
        pmvy = pmvx + 1;
        for (idx = 0; idx < 4; idx += 2) // unroll the loop, make 4 iterations to 2
        {
            // first/third row : 1,2,3 or 9,10,12
            // Strength = 2 for a whole row
            if (MbQ->nz_coeff[idx] != 0) *pStrength = 2;
            if (MbQ->nz_coeff[4+idx] != 0)
            {
                *pStrength = 2;
                *(pStrength + 4) = 2;
            }
            if (MbQ->nz_coeff[8+idx] != 0)
            {
                *(pStrength + 4) = 2;
                *(pStrength + 8) = 2;
            }
            if (MbQ->nz_coeff[12+idx] != 0) *(pStrength + 8) = 2;

            // Then Strength = 1
            if (*pStrength == 0)
            {
                //within the same 8x8 block, no need to check the reference id
                //only need to check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;

                tmp = *pmvy - *(pmvy - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStrength = 1;
            }

            pmvx += 8;
            pmvy += 8;
            pStr = pStrength + 4;

            if (*pStr == 0)
            {
                //check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            pmvx += 8;
            pmvy += 8;
            pStr = pStrength + 8;

            if (*pStr == 0)
            {
                //within the same 8x8 block, no need to check the reference id
                //only need to check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            // Second/fourth row: 5,6,7 or 14,15,16
            // Strength = 2 for a whole row
            if (MbQ->nz_coeff[idx+1] != 0) *(pStrength + 1) = 2;
            if (MbQ->nz_coeff[4+idx+1] != 0)
            {
                *(pStrength + 1) = 2;
                *(pStrength + 5) = 2;
            }
            if (MbQ->nz_coeff[8+idx+1] != 0)
            {
                *(pStrength + 5) = 2;
                *(pStrength + 9) = 2;
            }
            if (MbQ->nz_coeff[12+idx+1] != 0) *(pStrength + 9) = 2;

            // Then Strength = 1
            pmvx -= 14;
            pmvy -= 14; // -14 = -16 + 2
            pStr = pStrength + 1;
            if (*pStr == 0)
            {
                //within the same 8x8 block, no need to check the reference id
                //only need to check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            pmvx += 8;
            pmvy += 8;
            pStr = pStrength + 5;

            if (*pStr == 0)
            {
                //check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            pmvx += 8;
            pmvy += 8;
            pStr = pStrength + 9;

            if (*pStr == 0)
            {
                //within the same 8x8 block, no need to check the reference id
                //only need to check the |mv difference| >= 4
                tmp = *pmvx - *(pmvx - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;

                tmp = *pmvy - *(pmvy - 8);
                if (tmp < 0) tmp = -tmp;
                if (tmp >= 4) *pStr = 1;
            }

            // update some variables for the next two rows
            pmvx -= 14;
            pmvy -= 14; // -14 = -16 + 2
            pStrength += 2;

        } /* end of: for(idx=0; idx<2; idx++) */

    } /* end of: else if( MbQ->mbMode == AVC_I4 ...) */
}

/*
 *****************************************************************************************
 * \brief  Filters one edge of 16 (luma) or 8 (chroma) pel
 *****************************************************************************************
*/

void EdgeLoop_Luma_horizontal(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch)
{
    int  pel, ap = 0, aq = 0, Strng;
    int  C0, c0, dif, AbsDelta, tmp, tmp1;
    int  L2 = 0, L1, L0, R0, R1, R2 = 0, RL0;


    if (Strength[0] == 4)  /* INTRA strong filtering */
    {
        for (pel = 0; pel < 16; pel++)
        {
            R0  = SrcPtr[0];
            R1  = SrcPtr[pitch];
            L0  = SrcPtr[-pitch];
            L1  = SrcPtr[-(pitch<<1)];

            // |R0 - R1| < Beta
            tmp1 = R0 - R1;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp = (tmp1 - Beta);

            //|L0 - L1| < Beta
            tmp1 = L0 - L1;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp &= (tmp1 - Beta);

            //|R0 - L0| < Alpha
            AbsDelta = R0 - L0;
            if (AbsDelta < 0) AbsDelta = -AbsDelta;
            tmp &= (AbsDelta - Alpha);

            if (tmp < 0)
            {
                AbsDelta -= ((Alpha >> 2) + 2);
                R2 = SrcPtr[pitch<<1]; //inc2
                L2 = SrcPtr[-(pitch+(pitch<<1))]; // -inc3

                // |R0 - R2| < Beta && |R0 - L0| < (Alpha/4 + 2)
                tmp = R0 - R2;
                if (tmp < 0) tmp = -tmp;
                aq = AbsDelta & (tmp - Beta);

                // |L0 - L2| < Beta && |R0 - L0| < (Alpha/4 + 2)
                tmp = L0 - L2;
                if (tmp < 0) tmp = -tmp;
                ap = AbsDelta & (tmp - Beta);

                if (aq < 0)
                {
                    tmp = R1 + R0 + L0;
                    SrcPtr[0] = (L1 + (tmp << 1) +  R2 + 4) >> 3;
                    tmp += R2;
                    SrcPtr[pitch]  = (tmp + 2) >> 2;
                    SrcPtr[pitch<<1] = (((SrcPtr[(pitch+(pitch<<1))] + R2) << 1) + tmp + 4) >> 3;
                }
                else
                    SrcPtr[0] = ((R1 << 1) + R0 + L1 + 2) >> 2;

                if (ap < 0)
                {
                    tmp = L1 + R0 + L0;
                    SrcPtr[-pitch]  = (R1 + (tmp << 1) +  L2 + 4) >> 3;
                    tmp += L2;
                    SrcPtr[-(pitch<<1)] = (tmp + 2) >> 2;
                    SrcPtr[-(pitch+(pitch<<1))] = (((SrcPtr[-(pitch<<2)] + L2) << 1) + tmp + 4) >> 3;
                }
                else
                    SrcPtr[-pitch] = ((L1 << 1) + L0 + R1 + 2) >> 2;

            } /* if(tmp < 0) */

            SrcPtr ++; // Increment to next set of pixel

        } /* end of: for(pel=0; pel<16; pel++) */

    } /* if(Strength[0] == 4) */

    else   /* Normal filtering */
    {
        for (pel = 0; pel < 16; pel++)
        {
            Strng = Strength[pel >> 2];
            if (Strng)
            {
                R0  = SrcPtr[0];
                R1  = SrcPtr[pitch];
                L0  = SrcPtr[-pitch];
                L1  = SrcPtr[-(pitch<<1)]; // inc2

                //|R0 - L0| < Alpha
                tmp1 = R0 - L0;
                if (tmp1 < 0) tmp1 = -tmp1;
                tmp = (tmp1 - Alpha);

                // |R0 - R1| < Beta
                tmp1 = R0 - R1;
                if (tmp1 < 0) tmp1 = -tmp1;
                tmp &= (tmp1 - Beta);

                //|L0 - L1| < Beta
                tmp1 = L0 - L1;
                if (tmp1 < 0) tmp1 = -tmp1;
                tmp &= (tmp1 - Beta);

                if (tmp < 0)
                {
                    R2 = SrcPtr[pitch<<1]; //inc2
                    L2 = SrcPtr[-(pitch+(pitch<<1))]; // -inc3

                    // |R0 - R2| < Beta
                    tmp = R0 - R2;
                    if (tmp < 0) tmp = -tmp;
                    aq = tmp - Beta;

                    // |L0 - L2| < Beta
                    tmp = L0 - L2;
                    if (tmp < 0) tmp = -tmp;
                    ap = tmp - Beta;


                    c0 = C0 = clipTable[Strng];
                    if (ap < 0) c0++;
                    if (aq < 0) c0++;

                    //dif = IClip(-c0, c0, ((Delta << 2) + (L1 - R1) + 4) >> 3);
                    dif = (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3;
                    tmp = dif + c0;
                    if ((uint)tmp > (uint)c0 << 1)
                    {
                        tmp = ~(tmp >> 31);
                        dif = (tmp & (c0 << 1)) - c0;
                    }

                    //SrcPtr[0]    = (uint8)IClip(0, 255, R0 - dif);
                    //SrcPtr[-inc] = (uint8)IClip(0, 255, L0 + dif);
                    RL0 = R0 + L0;
                    R0 -= dif;
                    L0 += dif;
                    if ((uint)R0 > 255)
                    {
                        tmp = ~(R0 >> 31);
                        R0 = tmp & 255;
                    }
                    if ((uint)L0 > 255)
                    {
                        tmp = ~(L0 >> 31);
                        L0 = tmp & 255;
                    }
                    SrcPtr[-pitch] = L0;
                    SrcPtr[0] = R0;

                    if (C0 != 0) /* Multiple zeros in the clip tables */
                    {
                        if (aq < 0)  // SrcPtr[inc]   += IClip(-C0, C0,(R2 + ((RL0 + 1) >> 1) - (R1<<1)) >> 1);
                        {
                            R2 = (R2 + ((RL0 + 1) >> 1) - (R1 << 1)) >> 1;
                            tmp = R2 + C0;
                            if ((uint)tmp > (uint)C0 << 1)
                            {
                                tmp = ~(tmp >> 31);
                                R2 = (tmp & (C0 << 1)) - C0;
                            }
                            SrcPtr[pitch] += R2;
                        }

                        if (ap < 0)  //SrcPtr[-inc2] += IClip(-C0, C0,(L2 + ((RL0 + 1) >> 1) - (L1<<1)) >> 1);
                        {
                            L2 = (L2 + ((RL0 + 1) >> 1) - (L1 << 1)) >> 1;
                            tmp = L2 + C0;
                            if ((uint)tmp > (uint)C0 << 1)
                            {
                                tmp = ~(tmp >> 31);
                                L2 = (tmp & (C0 << 1)) - C0;
                            }
                            SrcPtr[-(pitch<<1)] += L2;
                        }
                    }

                } /* if(tmp < 0) */

            } /* end of:  if((Strng = Strength[pel >> 2])) */

            SrcPtr ++; // Increment to next set of pixel

        } /* for(pel=0; pel<16; pel++) */

    } /* else if(Strength[0] == 4) */
}

void EdgeLoop_Luma_vertical(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch)
{
    int  pel, ap = 1, aq = 1;
    int  C0, c0, dif, AbsDelta, Strng, tmp, tmp1;
    int  L2 = 0, L1, L0, R0, R1, R2 = 0;
    uint8 *ptr, *ptr1;
    uint R_in, L_in;
    uint R_out, L_out;


    if (Strength[0] == 4)  /* INTRA strong filtering */
    {

        for (pel = 0; pel < 16; pel++)
        {

            // Read 8 pels
            R_in = *((uint *)SrcPtr);       // R_in = {R3, R2, R1, R0}
            L_in = *((uint *)(SrcPtr - 4)); // L_in = {L0, L1, L2, L3}
            R1   = (R_in >> 8) & 0xff;
            R0   = R_in & 0xff;
            L0   = L_in >> 24;
            L1   = (L_in >> 16) & 0xff;

            // |R0 - R1| < Beta
            tmp1 = (R_in & 0xff) - R1;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp = (tmp1 - Beta);


            //|L0 - L1| < Beta
            tmp1 = (L_in >> 24) - L1;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp &= (tmp1 - Beta);

            //|R0 - L0| < Alpha
            AbsDelta = (R_in & 0xff) - (L_in >> 24);
            if (AbsDelta < 0) AbsDelta = -AbsDelta;
            tmp &= (AbsDelta - Alpha);

            if (tmp < 0)
            {
                AbsDelta -= ((Alpha >> 2) + 2);
                R2   = (R_in >> 16) & 0xff;
                L2   = (L_in >> 8) & 0xff;

                // |R0 - R2| < Beta && |R0 - L0| < (Alpha/4 + 2)
                tmp1 = (R_in & 0xff) - R2;
                if (tmp1 < 0) tmp1 = -tmp1;
                aq = AbsDelta & (tmp1 - Beta);

                // |L0 - L2| < Beta && |R0 - L0| < (Alpha/4 + 2)
                tmp1 = (L_in >> 24) - L2;
                if (tmp1 < 0) tmp1 = -tmp1;
                ap = AbsDelta & (tmp1 - Beta);


                ptr = SrcPtr;
                if (aq < 0)
                {
                    R_out = (R_in >> 24) << 24; // Keep R3 at the fourth byte

                    tmp  = R0 + L0 + R1;
                    R_out |= (((tmp << 1) +  L1 + R2 + 4) >> 3);
                    tmp += R2;
                    R_out |= (((tmp + 2) >> 2) << 8);
                    tmp1 = ((R_in >> 24) + R2) << 1;
                    R_out |= (((tmp1 + tmp + 4) >> 3) << 16);

                    *((uint *)SrcPtr) = R_out;
                }
                else
                    *ptr = ((R1 << 1) + R0 + L1 + 2) >> 2;


                if (ap < 0)
                {
                    L_out = (L_in << 24) >> 24; // Keep L3 at the first byte

                    tmp  = R0 + L0 + L1;
                    L_out |= ((((tmp << 1) + R1 + L2 + 4) >> 3) << 24);
                    tmp += L2;
                    L_out |= (((tmp + 2) >> 2) << 16);
                    tmp1 = ((L_in & 0xff) + L2) << 1;
                    L_out |= (((tmp1 + tmp + 4) >> 3) << 8);

                    *((uint *)(SrcPtr - 4)) = L_out;
                }
                else
                    *(--ptr) = ((L1 << 1) + L0 + R1 + 2) >> 2;

            } /* if(tmp < 0) */

            SrcPtr += pitch;    // Increment to next set of pixel

        } /* end of: for(pel=0; pel<16; pel++) */

    } /* if(Strength[0] == 4) */

    else   /* Normal filtering */
    {

        for (pel = 0; pel < 16; pel++)
        {
            Strng = Strength[pel >> 2];
            if (Strng)
            {
                // Read 8 pels
                R_in = *((uint *)SrcPtr);       // R_in = {R3, R2, R1, R0}
                L_in = *((uint *)(SrcPtr - 4)); // L_in = {L0, L1, L2, L3}
                R1   = (R_in >> 8) & 0xff;
                R0   = R_in & 0xff;
                L0   = L_in >> 24;
                L1   = (L_in >> 16) & 0xff;

                //|R0 - L0| < Alpha
                tmp = R0 - L0;
                if (tmp < 0) tmp = -tmp;
                tmp -= Alpha;

                // |R0 - R1| < Beta
                tmp1 = R0 - R1;
                if (tmp1 < 0) tmp1 = -tmp1;
                tmp &= (tmp1 - Beta);

                //|L0 - L1| < Beta
                tmp1 = L0 - L1;
                if (tmp1 < 0) tmp1 = -tmp1;
                tmp &= (tmp1 - Beta);

                if (tmp < 0)
                {
                    L2 = SrcPtr[-3];
                    R2 = SrcPtr[2];

                    // |R0 - R2| < Beta
                    tmp = R0 - R2;
                    if (tmp < 0) tmp = -tmp;
                    aq = tmp - Beta;

                    // |L0 - L2| < Beta
                    tmp = L0 - L2;
                    if (tmp < 0) tmp = -tmp;
                    ap = tmp - Beta;


                    c0 = C0 = clipTable[Strng];
                    if (ap < 0) c0++;
                    if (aq < 0) c0++;

                    //dif = IClip(-c0, c0, ((Delta << 2) + (L1 - R1) + 4) >> 3);
                    dif = (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3;
                    tmp = dif + c0;
                    if ((uint)tmp > (uint)c0 << 1)
                    {
                        tmp = ~(tmp >> 31);
                        dif = (tmp & (c0 << 1)) - c0;
                    }

                    ptr = SrcPtr;
                    ptr1 = SrcPtr - 1;
                    //SrcPtr[0]    = (uint8)IClip(0, 255, R0 - dif);
                    //SrcPtr[-inc] = (uint8)IClip(0, 255, L0 + dif);
                    R_in = R0 - dif;
                    L_in = L0 + dif; /* cannot re-use R0 and L0 here */
                    if ((uint)R_in > 255)
                    {
                        tmp = ~((int)R_in >> 31);
                        R_in = tmp & 255;
                    }
                    if ((uint)L_in > 255)
                    {
                        tmp = ~((int)L_in >> 31);
                        L_in = tmp & 255;
                    }
                    *ptr1-- = L_in;
                    *ptr++  = R_in;

                    if (C0 != 0) // Multiple zeros in the clip tables
                    {
                        if (ap < 0)  //SrcPtr[-inc2] += IClip(-C0, C0,(L2 + ((RL0 + 1) >> 1) - (L1<<1)) >> 1);
                        {
                            L2 = (L2 + ((R0 + L0 + 1) >> 1) - (L1 << 1)) >> 1;
                            tmp = L2 + C0;
                            if ((uint)tmp > (uint)C0 << 1)
                            {
                                tmp = ~(tmp >> 31);
                                L2 = (tmp & (C0 << 1)) - C0;
                            }
                            *ptr1 += L2;
                        }

                        if (aq < 0)  // SrcPtr[inc] += IClip(-C0, C0,(R2 + ((RL0 + 1) >> 1) - (R1<<1)) >> 1);
                        {
                            R2 = (R2 + ((R0 + L0 + 1) >> 1) - (R1 << 1)) >> 1;
                            tmp = R2 + C0;
                            if ((uint)tmp > (uint)C0 << 1)
                            {
                                tmp = ~(tmp >> 31);
                                R2 = (tmp & (C0 << 1)) - C0;
                            }
                            *ptr += R2;
                        }
                    }

                } /* if(tmp < 0) */

            } /* end of:  if((Strng = Strength[pel >> 2])) */

            SrcPtr += pitch;    // Increment to next set of pixel

        } /* for(pel=0; pel<16; pel++) */

    } /* else if(Strength[0] == 4) */

}

void EdgeLoop_Chroma_vertical(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch)
{
    int     pel, Strng;
    int     c0, dif;
    int     L1, L0, R0, R1, tmp, tmp1;
    uint8   *ptr;
    uint    R_in, L_in;


    for (pel = 0; pel < 16; pel++)
    {
        Strng = Strength[pel>>2];
        if (Strng)
        {
            // Read 8 pels
            R_in = *((uint *)SrcPtr);       // R_in = {R3, R2, R1, R0}
            L_in = *((uint *)(SrcPtr - 4)); // L_in = {L0, L1, L2, L3}
            R1   = (R_in >> 8) & 0xff;
            R0   = R_in & 0xff;
            L0   = L_in >> 24;
            L1   = (L_in >> 16) & 0xff;

            // |R0 - R1| < Beta
            tmp1 = R0 - R1;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp = (tmp1 - Beta);

            //|L0 - L1| < Beta
            tmp1 = L0 - L1;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp &= (tmp1 - Beta);

            //|R0 - L0| < Alpha
            tmp1 = R0 - L0;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp &= (tmp1 - Alpha);

            if (tmp < 0)
            {
                ptr = SrcPtr;
                if (Strng == 4) /* INTRA strong filtering */
                {
                    *ptr-- = ((R1 << 1) + R0 + L1 + 2) >> 2;
                    *ptr   = ((L1 << 1) + L0 + R1 + 2) >> 2;
                }
                else  /* normal filtering */
                {
                    c0  = clipTable[Strng] + 1;
                    //dif = IClip(-c0, c0, ((Delta << 2) + (L1 - R1) + 4) >> 3);
                    dif = (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3;
                    tmp = dif + c0;
                    if ((uint)tmp > (uint)c0 << 1)
                    {
                        tmp = ~(tmp >> 31);
                        dif = (tmp & (c0 << 1)) - c0;
                    }

                    //SrcPtr[0]    = (uint8)IClip(0, 255, R0 - dif);
                    //SrcPtr[-inc] = (uint8)IClip(0, 255, L0 + dif);
                    L0 += dif;
                    R0 -= dif;
                    if ((uint)L0 > 255)
                    {
                        tmp = ~(L0 >> 31);
                        L0 = tmp & 255;
                    }
                    if ((uint)R0 > 255)
                    {
                        tmp = ~(R0 >> 31);
                        R0 = tmp & 255;
                    }

                    *ptr-- = R0;
                    *ptr = L0;
                }
            }
            pel ++;
            SrcPtr += pitch;   // Increment to next set of pixel

        } /* end of: if((Strng = Strength[pel >> 2])) */
        else
        {
            pel += 3;
            SrcPtr += (pitch << 1); //PtrInc << 1;
        }

    } /* end of: for(pel=0; pel<16; pel++) */
}


void EdgeLoop_Chroma_horizontal(uint8* SrcPtr, uint8 *Strength, int Alpha, int Beta, int *clipTable, int pitch)
{
    int  pel, Strng;
    int  c0, dif;
    int  L1, L0, R0, R1, tmp, tmp1;

    for (pel = 0; pel < 16; pel++)
    {
        Strng = Strength[pel>>2];
        if (Strng)
        {
            R0  = SrcPtr[0];
            L0  = SrcPtr[-pitch];
            L1  = SrcPtr[-(pitch<<1)]; //inc2
            R1  = SrcPtr[pitch];

            // |R0 - R1| < Beta
            tmp1 = R0 - R1;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp = (tmp1 - Beta);

            //|L0 - L1| < Beta
            tmp1 = L0 - L1;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp &= (tmp1 - Beta);

            //|R0 - L0| < Alpha
            tmp1 = R0 - L0;
            if (tmp1 < 0) tmp1 = -tmp1;
            tmp &= (tmp1 - Alpha);

            if (tmp < 0)
            {
                if (Strng == 4) /* INTRA strong filtering */
                {
                    SrcPtr[0]      = ((R1 << 1) + R0 + L1 + 2) >> 2;
                    SrcPtr[-pitch] = ((L1 << 1) + L0 + R1 + 2) >> 2;
                }
                else  /* normal filtering */
                {
                    c0  = clipTable[Strng] + 1;
                    //dif = IClip(-c0, c0, ((Delta << 2) + (L1 - R1) + 4) >> 3);
                    dif = (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3;
                    tmp = dif + c0;
                    if ((uint)tmp > (uint)c0 << 1)
                    {
                        tmp = ~(tmp >> 31);
                        dif = (tmp & (c0 << 1)) - c0;
                    }

                    //SrcPtr[-inc] = (uint8)IClip(0, 255, L0 + dif);
                    //SrcPtr[0]    = (uint8)IClip(0, 255, R0 - dif);
                    L0 += dif;
                    R0 -= dif;
                    if ((uint)L0 > 255)
                    {
                        tmp = ~(L0 >> 31);
                        L0 = tmp & 255;
                    }
                    if ((uint)R0 > 255)
                    {
                        tmp = ~(R0 >> 31);
                        R0 = tmp & 255;
                    }
                    SrcPtr[0] = R0;
                    SrcPtr[-pitch] = L0;
                }
            }

            pel ++;
            SrcPtr ++; // Increment to next set of pixel

        } /* end of: if((Strng = Strength[pel >> 2])) */
        else
        {
            pel += 3;
            SrcPtr += 2;
        }

    } /* end of: for(pel=0; pel<16; pel++) */
}




