/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * 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.
 */

/*------------------------------------------------------------------------------

    Table of contents

     1. Include headers
     2. External compiler flags
     3. Module defines
     4. Local function prototypes
     5. Functions
          h264bsdIntraPrediction
          h264bsdGetNeighbourPels
          h264bsdIntra16x16Prediction
          h264bsdIntra4x4Prediction
          h264bsdIntraChromaPrediction
          h264bsdAddResidual
          Intra16x16VerticalPrediction
          Intra16x16HorizontalPrediction
          Intra16x16DcPrediction
          Intra16x16PlanePrediction
          IntraChromaDcPrediction
          IntraChromaHorizontalPrediction
          IntraChromaVerticalPrediction
          IntraChromaPlanePrediction
          Get4x4NeighbourPels
          Write4x4To16x16
          Intra4x4VerticalPrediction
          Intra4x4HorizontalPrediction
          Intra4x4DcPrediction
          Intra4x4DiagonalDownLeftPrediction
          Intra4x4DiagonalDownRightPrediction
          Intra4x4VerticalRightPrediction
          Intra4x4HorizontalDownPrediction
          Intra4x4VerticalLeftPrediction
          Intra4x4HorizontalUpPrediction
          DetermineIntra4x4PredMode

------------------------------------------------------------------------------*/

/*------------------------------------------------------------------------------
    1. Include headers
------------------------------------------------------------------------------*/

#include "h264bsd_intra_prediction.h"
#include "h264bsd_util.h"
#include "h264bsd_macroblock_layer.h"
#include "h264bsd_neighbour.h"
#include "h264bsd_image.h"

#ifdef H264DEC_OMXDL
#include "omxtypes.h"
#include "omxVC.h"
#endif /* H264DEC_OMXDL */

/*------------------------------------------------------------------------------
    2. External compiler flags
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
    3. Module defines
------------------------------------------------------------------------------*/

/* Switch off the following Lint messages for this file:
 * Info 702: Shift right of signed quantity (int)
 */
/*lint -e702 */


/* x- and y-coordinates for each block */
const u32 h264bsdBlockX[16] =
    { 0, 4, 0, 4, 8, 12, 8, 12, 0, 4, 0, 4, 8, 12, 8, 12 };
const u32 h264bsdBlockY[16] =
    { 0, 0, 4, 4, 0, 0, 4, 4, 8, 8, 12, 12, 8, 8, 12, 12 };

const u8 h264bsdClip[1280] =
{
    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,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,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,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,
    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,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,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,52,53,54,55,56,57,58,59,60,61,62,63,
    64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
    80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
    96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
    112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
    128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
    144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
    160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
    176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
    192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
    208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
    224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
    240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
};

#ifndef H264DEC_OMXDL
/*------------------------------------------------------------------------------
    4. Local function prototypes
------------------------------------------------------------------------------*/
static void Get4x4NeighbourPels(u8 *a, u8 *l, u8 *data, u8 *above, u8 *left,
    u32 blockNum);
static void Intra16x16VerticalPrediction(u8 *data, u8 *above);
static void Intra16x16HorizontalPrediction(u8 *data, u8 *left);
static void Intra16x16DcPrediction(u8 *data, u8 *above, u8 *left,
    u32 A, u32 B);
static void Intra16x16PlanePrediction(u8 *data, u8 *above, u8 *left);
static void IntraChromaDcPrediction(u8 *data, u8 *above, u8 *left,
    u32 A, u32 B);
static void IntraChromaHorizontalPrediction(u8 *data, u8 *left);
static void IntraChromaVerticalPrediction(u8 *data, u8 *above);
static void IntraChromaPlanePrediction(u8 *data, u8 *above, u8 *left);

static void Intra4x4VerticalPrediction(u8 *data, u8 *above);
static void Intra4x4HorizontalPrediction(u8 *data, u8 *left);
static void Intra4x4DcPrediction(u8 *data, u8 *above, u8 *left, u32 A, u32 B);
static void Intra4x4DiagonalDownLeftPrediction(u8 *data, u8 *above);
static void Intra4x4DiagonalDownRightPrediction(u8 *data, u8 *above, u8 *left);
static void Intra4x4VerticalRightPrediction(u8 *data, u8 *above, u8 *left);
static void Intra4x4HorizontalDownPrediction(u8 *data, u8 *above, u8 *left);
static void Intra4x4VerticalLeftPrediction(u8 *data, u8 *above);
static void Intra4x4HorizontalUpPrediction(u8 *data, u8 *left);
void h264bsdAddResidual(u8 *data, i32 *residual, u32 blockNum);

static void Write4x4To16x16(u8 *data, u8 *data4x4, u32 blockNum);
#endif /* H264DEC_OMXDL */

static u32 DetermineIntra4x4PredMode(macroblockLayer_t *pMbLayer,
    u32 available, neighbour_t *nA, neighbour_t *nB, u32 index,
    mbStorage_t *nMbA, mbStorage_t *nMbB);


#ifdef H264DEC_OMXDL

/*------------------------------------------------------------------------------

    Function: h264bsdIntra16x16Prediction

        Functional description:
          Perform intra 16x16 prediction mode for luma pixels and add
          residual into prediction. The resulting luma pixels are
          stored in macroblock array 'data'.

------------------------------------------------------------------------------*/
u32 h264bsdIntra16x16Prediction(mbStorage_t *pMb, u8 *data, u8 *ptr,
                                u32 width, u32 constrainedIntraPred)
{

/* Variables */

    u32 availableA, availableB, availableD;
    OMXResult omxRes;

/* Code */
    ASSERT(pMb);
    ASSERT(data);
    ASSERT(ptr);
    ASSERT(h264bsdPredModeIntra16x16(pMb->mbType) < 4);

    availableA = h264bsdIsNeighbourAvailable(pMb, pMb->mbA);
    if (availableA && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbA->mbType) == PRED_MODE_INTER))
        availableA = HANTRO_FALSE;
    availableB = h264bsdIsNeighbourAvailable(pMb, pMb->mbB);
    if (availableB && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbB->mbType) == PRED_MODE_INTER))
        availableB = HANTRO_FALSE;
    availableD = h264bsdIsNeighbourAvailable(pMb, pMb->mbD);
    if (availableD && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbD->mbType) == PRED_MODE_INTER))
        availableD = HANTRO_FALSE;

    omxRes = omxVCM4P10_PredictIntra_16x16( (ptr-1),
                                    (ptr - width),
                                    (ptr - width-1),
                                    data,
                                    (i32)width,
                                    16,
                                    (OMXVCM4P10Intra16x16PredMode)
                                    h264bsdPredModeIntra16x16(pMb->mbType),
                                    (i32)(availableB + (availableA<<1) +
                                     (availableD<<5)) );
    if (omxRes != OMX_Sts_NoErr)
        return HANTRO_NOK;
    else
        return(HANTRO_OK);
}

/*------------------------------------------------------------------------------

    Function: h264bsdIntra4x4Prediction

        Functional description:
          Perform intra 4x4 prediction for luma pixels and add residual
          into prediction. The resulting luma pixels are stored in
          macroblock array 'data'. The intra 4x4 prediction mode for each
          block is stored in 'pMb' structure.

------------------------------------------------------------------------------*/
u32 h264bsdIntra4x4Prediction(mbStorage_t *pMb, u8 *data,
                              macroblockLayer_t *mbLayer,
                              u8 *ptr, u32 width,
                              u32 constrainedIntraPred, u32 block)
{

/* Variables */
    u32 mode;
    neighbour_t neighbour, neighbourB;
    mbStorage_t *nMb, *nMb2;
    u32 availableA, availableB, availableC, availableD;

    OMXResult omxRes;
    u32 x, y;
    u8 *l, *a, *al;
/* Code */
    ASSERT(pMb);
    ASSERT(data);
    ASSERT(mbLayer);
    ASSERT(ptr);
    ASSERT(pMb->intra4x4PredMode[block] < 9);

    neighbour = *h264bsdNeighbour4x4BlockA(block);
    nMb = h264bsdGetNeighbourMb(pMb, neighbour.mb);
    availableA = h264bsdIsNeighbourAvailable(pMb, nMb);
    if (availableA && constrainedIntraPred &&
       ( h264bsdMbPartPredMode(nMb->mbType) == PRED_MODE_INTER) )
    {
        availableA = HANTRO_FALSE;
    }

    neighbourB = *h264bsdNeighbour4x4BlockB(block);
    nMb2 = h264bsdGetNeighbourMb(pMb, neighbourB.mb);
    availableB = h264bsdIsNeighbourAvailable(pMb, nMb2);
    if (availableB && constrainedIntraPred &&
       ( h264bsdMbPartPredMode(nMb2->mbType) == PRED_MODE_INTER) )
    {
        availableB = HANTRO_FALSE;
    }

    mode = DetermineIntra4x4PredMode(mbLayer,
        (u32)(availableA && availableB),
        &neighbour, &neighbourB, block, nMb, nMb2);
    pMb->intra4x4PredMode[block] = (u8)mode;

    neighbour = *h264bsdNeighbour4x4BlockC(block);
    nMb = h264bsdGetNeighbourMb(pMb, neighbour.mb);
    availableC = h264bsdIsNeighbourAvailable(pMb, nMb);
    if (availableC && constrainedIntraPred &&
       ( h264bsdMbPartPredMode(nMb->mbType) == PRED_MODE_INTER) )
    {
        availableC = HANTRO_FALSE;
    }

    neighbour = *h264bsdNeighbour4x4BlockD(block);
    nMb = h264bsdGetNeighbourMb(pMb, neighbour.mb);
    availableD = h264bsdIsNeighbourAvailable(pMb, nMb);
    if (availableD && constrainedIntraPred &&
       ( h264bsdMbPartPredMode(nMb->mbType) == PRED_MODE_INTER) )
    {
        availableD = HANTRO_FALSE;
    }

    x = h264bsdBlockX[block];
    y = h264bsdBlockY[block];

    if (y == 0)
        a = ptr - width + x;
    else
        a = data-16;

    if (x == 0)
        l = ptr + y * width -1;
    else
    {
        l = data-1;
        width = 16;
    }

    if (x == 0)
        al = l-width;
    else
        al = a-1;

    omxRes = omxVCM4P10_PredictIntra_4x4( l,
                                          a,
                                          al,
                                          data,
                                          (i32)width,
                                          16,
                                          (OMXVCM4P10Intra4x4PredMode)mode,
                                          (i32)(availableB +
                                          (availableA<<1) +
                                          (availableD<<5) +
                                          (availableC<<6)) );
    if (omxRes != OMX_Sts_NoErr)
        return HANTRO_NOK;

    return(HANTRO_OK);

}

/*------------------------------------------------------------------------------

    Function: h264bsdIntraChromaPrediction

        Functional description:
          Perform intra prediction for chroma pixels and add residual
          into prediction. The resulting chroma pixels are stored in 'data'.

------------------------------------------------------------------------------*/
u32 h264bsdIntraChromaPrediction(mbStorage_t *pMb, u8 *data, image_t *image,
                                        u32 predMode, u32 constrainedIntraPred)
{

/* Variables */

    u32 availableA, availableB, availableD;
    OMXResult omxRes;
    u8 *ptr;
    u32 width;

/* Code */
    ASSERT(pMb);
    ASSERT(data);
    ASSERT(image);
    ASSERT(predMode < 4);

    availableA = h264bsdIsNeighbourAvailable(pMb, pMb->mbA);
    if (availableA && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbA->mbType) == PRED_MODE_INTER))
        availableA = HANTRO_FALSE;
    availableB = h264bsdIsNeighbourAvailable(pMb, pMb->mbB);
    if (availableB && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbB->mbType) == PRED_MODE_INTER))
        availableB = HANTRO_FALSE;
    availableD = h264bsdIsNeighbourAvailable(pMb, pMb->mbD);
    if (availableD && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbD->mbType) == PRED_MODE_INTER))
        availableD = HANTRO_FALSE;

    ptr = image->cb;
    width = image->width*8;

    omxRes = omxVCM4P10_PredictIntraChroma_8x8( (ptr-1),
                                                (ptr - width),
                                                (ptr - width -1),
                                                data,
                                                (i32)width,
                                                8,
                                                (OMXVCM4P10IntraChromaPredMode)
                                                predMode,
                                                (i32)(availableB +
                                                 (availableA<<1) +
                                                 (availableD<<5)) );
    if (omxRes != OMX_Sts_NoErr)
        return HANTRO_NOK;

    /* advance pointers */
    data += 64;
    ptr = image->cr;

    omxRes = omxVCM4P10_PredictIntraChroma_8x8( (ptr-1),
                                                (ptr - width),
                                                (ptr - width -1),
                                                data,
                                                (i32)width,
                                                8,
                                                (OMXVCM4P10IntraChromaPredMode)
                                                predMode,
                                                (i32)(availableB +
                                                 (availableA<<1) +
                                                 (availableD<<5)) );
    if (omxRes != OMX_Sts_NoErr)
        return HANTRO_NOK;

    return(HANTRO_OK);

}


#else /* H264DEC_OMXDL */


/*------------------------------------------------------------------------------

    Function: h264bsdIntraPrediction

        Functional description:
          Processes one intra macroblock. Performs intra prediction using
          specified prediction mode. Writes the final macroblock
          (prediction + residual) into the output image (image)

        Inputs:
          pMb           pointer to macroblock specific information
          mbLayer       pointer to current macroblock data from stream
          image         pointer to output image
          mbNum         current macroblock number
          constrainedIntraPred  flag specifying if neighbouring inter
                                macroblocks are used in intra prediction
          data          pointer where output macroblock will be stored

        Outputs:
          pMb           structure is updated with current macroblock
          image         current macroblock is written into image
          data          current macroblock is stored here

        Returns:
          HANTRO_OK     success
          HANTRO_NOK    error in intra prediction

------------------------------------------------------------------------------*/
u32 h264bsdIntraPrediction(mbStorage_t *pMb, macroblockLayer_t *mbLayer,
    image_t *image, u32 mbNum, u32 constrainedIntraPred, u8 *data)
{

/* Variables */

    /* pelAbove and pelLeft contain samples above and left to the current
     * macroblock. Above array contains also sample above-left to the current
     * mb as well as 4 samples above-right to the current mb (latter only for
     * luma) */
    /* lumD + lumB + lumC + cbD + cbB + crD + crB */
    u8 pelAbove[1 + 16 + 4 + 1 + 8 + 1 + 8];
    /* lumA + cbA + crA */
    u8 pelLeft[16 + 8 + 8];
    u32 tmp;

/* Code */

    ASSERT(pMb);
    ASSERT(image);
    ASSERT(mbNum < image->width * image->height);
    ASSERT(h264bsdMbPartPredMode(pMb->mbType) != PRED_MODE_INTER);

    h264bsdGetNeighbourPels(image, pelAbove, pelLeft, mbNum);

    if (h264bsdMbPartPredMode(pMb->mbType) == PRED_MODE_INTRA16x16)
    {
        tmp = h264bsdIntra16x16Prediction(pMb, data, mbLayer->residual.level,
            pelAbove, pelLeft, constrainedIntraPred);
        if (tmp != HANTRO_OK)
            return(tmp);
    }
    else
    {
        tmp = h264bsdIntra4x4Prediction(pMb, data, mbLayer,
            pelAbove, pelLeft, constrainedIntraPred);
        if (tmp != HANTRO_OK)
            return(tmp);
    }

    tmp = h264bsdIntraChromaPrediction(pMb, data + 256,
            mbLayer->residual.level+16, pelAbove + 21, pelLeft + 16,
            mbLayer->mbPred.intraChromaPredMode, constrainedIntraPred);
    if (tmp != HANTRO_OK)
        return(tmp);

    /* if decoded flag > 1 -> mb has already been successfully decoded and
     * written to output -> do not write again */
    if (pMb->decoded > 1)
        return HANTRO_OK;

    h264bsdWriteMacroblock(image, data);

    return(HANTRO_OK);

}

/*------------------------------------------------------------------------------

    Function: h264bsdGetNeighbourPels

        Functional description:
          Get pixel values from neighbouring macroblocks into 'above'
          and 'left' arrays.

------------------------------------------------------------------------------*/

void h264bsdGetNeighbourPels(image_t *image, u8 *above, u8 *left, u32 mbNum)
{

/* Variables */

    u32 i;
    u32 width, picSize;
    u8 *ptr, *tmp;
    u32 row, col;

/* Code */

    ASSERT(image);
    ASSERT(above);
    ASSERT(left);
    ASSERT(mbNum < image->width * image->height);

    if (!mbNum)
        return;

    width = image->width;
    picSize = width * image->height;
    row = mbNum / width;
    col = mbNum - row * width;

    width *= 16;
    ptr = image->data + row * 16 * width  + col * 16;

    /* note that luma samples above-right to current macroblock do not make
     * sense when current mb is the right-most mb in a row. Same applies to
     * sample above-left if col is zero. However, usage of pels in prediction
     * is controlled by neighbour availability information in actual prediction
     * process */
    if (row)
    {
        tmp = ptr - (width + 1);
        for (i = 21; i--;)
            *above++ = *tmp++;
    }

    if (col)
    {
        ptr--;
        for (i = 16; i--; ptr+=width)
            *left++ = *ptr;
    }

    width >>= 1;
    ptr = image->data + picSize * 256 + row * 8 * width  + col * 8;

    if (row)
    {
        tmp = ptr - (width + 1);
        for (i = 9; i--;)
            *above++ = *tmp++;
        tmp += (picSize * 64) - 9;
        for (i = 9; i--;)
            *above++ = *tmp++;
    }

    if (col)
    {
        ptr--;
        for (i = 8; i--; ptr+=width)
            *left++ = *ptr;
        ptr += (picSize * 64) - 8 * width;
        for (i = 8; i--; ptr+=width)
            *left++ = *ptr;
    }
}

/*------------------------------------------------------------------------------

    Function: Intra16x16Prediction

        Functional description:
          Perform intra 16x16 prediction mode for luma pixels and add
          residual into prediction. The resulting luma pixels are
          stored in macroblock array 'data'.

------------------------------------------------------------------------------*/

u32 h264bsdIntra16x16Prediction(mbStorage_t *pMb, u8 *data, i32 residual[][16],
                                u8 *above, u8 *left, u32 constrainedIntraPred)
{

/* Variables */

    u32 i;
    u32 availableA, availableB, availableD;

/* Code */

    ASSERT(data);
    ASSERT(residual);
    ASSERT(above);
    ASSERT(left);
    ASSERT(h264bsdPredModeIntra16x16(pMb->mbType) < 4);

    availableA = h264bsdIsNeighbourAvailable(pMb, pMb->mbA);
    if (availableA && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbA->mbType) == PRED_MODE_INTER))
        availableA = HANTRO_FALSE;
    availableB = h264bsdIsNeighbourAvailable(pMb, pMb->mbB);
    if (availableB && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbB->mbType) == PRED_MODE_INTER))
        availableB = HANTRO_FALSE;
    availableD = h264bsdIsNeighbourAvailable(pMb, pMb->mbD);
    if (availableD && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbD->mbType) == PRED_MODE_INTER))
        availableD = HANTRO_FALSE;

    switch(h264bsdPredModeIntra16x16(pMb->mbType))
    {
        case 0: /* Intra_16x16_Vertical */
            if (!availableB)
                return(HANTRO_NOK);
            Intra16x16VerticalPrediction(data, above+1);
            break;

        case 1: /* Intra_16x16_Horizontal */
            if (!availableA)
                return(HANTRO_NOK);
            Intra16x16HorizontalPrediction(data, left);
            break;

        case 2: /* Intra_16x16_DC */
            Intra16x16DcPrediction(data, above+1, left, availableA, availableB);
            break;

        default: /* case 3: Intra_16x16_Plane */
            if (!availableA || !availableB || !availableD)
                return(HANTRO_NOK);
            Intra16x16PlanePrediction(data, above+1, left);
            break;
    }
    /* add residual */
    for (i = 0; i < 16; i++)
        h264bsdAddResidual(data, residual[i], i);

    return(HANTRO_OK);

}

/*------------------------------------------------------------------------------

    Function: Intra4x4Prediction

        Functional description:
          Perform intra 4x4 prediction for luma pixels and add residual
          into prediction. The resulting luma pixels are stored in
          macroblock array 'data'. The intra 4x4 prediction mode for each
          block is stored in 'pMb' structure.

------------------------------------------------------------------------------*/

u32 h264bsdIntra4x4Prediction(mbStorage_t *pMb, u8 *data,
                              macroblockLayer_t *mbLayer, u8 *above,
                              u8 *left, u32 constrainedIntraPred)
{

/* Variables */

    u32 block;
    u32 mode;
    neighbour_t neighbour, neighbourB;
    mbStorage_t *nMb, *nMb2;
    u8 a[1 + 4 + 4], l[1 + 4];
    u32 data4x4[4];
    u32 availableA, availableB, availableC, availableD;

/* Code */

    ASSERT(data);
    ASSERT(mbLayer);
    ASSERT(above);
    ASSERT(left);

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

        ASSERT(pMb->intra4x4PredMode[block] < 9);

        neighbour = *h264bsdNeighbour4x4BlockA(block);
        nMb = h264bsdGetNeighbourMb(pMb, neighbour.mb);
        availableA = h264bsdIsNeighbourAvailable(pMb, nMb);
        if (availableA && constrainedIntraPred &&
           ( h264bsdMbPartPredMode(nMb->mbType) == PRED_MODE_INTER) )
        {
            availableA = HANTRO_FALSE;
        }

        neighbourB = *h264bsdNeighbour4x4BlockB(block);
        nMb2 = h264bsdGetNeighbourMb(pMb, neighbourB.mb);
        availableB = h264bsdIsNeighbourAvailable(pMb, nMb2);
        if (availableB && constrainedIntraPred &&
           ( h264bsdMbPartPredMode(nMb2->mbType) == PRED_MODE_INTER) )
        {
            availableB = HANTRO_FALSE;
        }

        mode = DetermineIntra4x4PredMode(mbLayer,
            (u32)(availableA && availableB),
            &neighbour, &neighbourB, block, nMb, nMb2);
        pMb->intra4x4PredMode[block] = (u8)mode;

        neighbour = *h264bsdNeighbour4x4BlockC(block);
        nMb = h264bsdGetNeighbourMb(pMb, neighbour.mb);
        availableC = h264bsdIsNeighbourAvailable(pMb, nMb);
        if (availableC && constrainedIntraPred &&
           ( h264bsdMbPartPredMode(nMb->mbType) == PRED_MODE_INTER) )
        {
            availableC = HANTRO_FALSE;
        }

        neighbour = *h264bsdNeighbour4x4BlockD(block);
        nMb = h264bsdGetNeighbourMb(pMb, neighbour.mb);
        availableD = h264bsdIsNeighbourAvailable(pMb, nMb);
        if (availableD && constrainedIntraPred &&
           ( h264bsdMbPartPredMode(nMb->mbType) == PRED_MODE_INTER) )
        {
            availableD = HANTRO_FALSE;
        }

        Get4x4NeighbourPels(a, l, data, above, left, block);

        switch(mode)
        {
            case 0: /* Intra_4x4_Vertical */
                if (!availableB)
                    return(HANTRO_NOK);
                Intra4x4VerticalPrediction((u8*)data4x4, a + 1);
                break;
            case 1: /* Intra_4x4_Horizontal */
                if (!availableA)
                    return(HANTRO_NOK);
                Intra4x4HorizontalPrediction((u8*)data4x4, l + 1);
                break;
            case 2: /* Intra_4x4_DC */
                Intra4x4DcPrediction((u8*)data4x4, a + 1, l + 1,
                    availableA, availableB);
                break;
            case 3: /* Intra_4x4_Diagonal_Down_Left */
                if (!availableB)
                    return(HANTRO_NOK);
                if (!availableC)
                {
                    a[5] = a[6] = a[7] = a[8] = a[4];
                }
                Intra4x4DiagonalDownLeftPrediction((u8*)data4x4, a + 1);
                break;
            case 4: /* Intra_4x4_Diagonal_Down_Right */
                if (!availableA || !availableB || !availableD)
                    return(HANTRO_NOK);
                Intra4x4DiagonalDownRightPrediction((u8*)data4x4, a + 1, l + 1);
                break;
            case 5: /* Intra_4x4_Vertical_Right */
                if (!availableA || !availableB || !availableD)
                    return(HANTRO_NOK);
                Intra4x4VerticalRightPrediction((u8*)data4x4, a + 1, l + 1);
                break;
            case 6: /* Intra_4x4_Horizontal_Down */
                if (!availableA || !availableB || !availableD)
                    return(HANTRO_NOK);
                Intra4x4HorizontalDownPrediction((u8*)data4x4, a + 1, l + 1);
                break;
            case 7: /* Intra_4x4_Vertical_Left */
                if (!availableB)
                    return(HANTRO_NOK);
                if (!availableC)
                {
                    a[5] = a[6] = a[7] = a[8] = a[4];
                }
                Intra4x4VerticalLeftPrediction((u8*)data4x4, a + 1);
                break;
            default: /* case 8 Intra_4x4_Horizontal_Up */
                if (!availableA)
                    return(HANTRO_NOK);
                Intra4x4HorizontalUpPrediction((u8*)data4x4, l + 1);
                break;
        }

        Write4x4To16x16(data, (u8*)data4x4, block);
        h264bsdAddResidual(data, mbLayer->residual.level[block], block);
    }

    return(HANTRO_OK);

}

/*------------------------------------------------------------------------------

    Function: IntraChromaPrediction

        Functional description:
          Perform intra prediction for chroma pixels and add residual
          into prediction. The resulting chroma pixels are stored in 'data'.

------------------------------------------------------------------------------*/

u32 h264bsdIntraChromaPrediction(mbStorage_t *pMb, u8 *data, i32 residual[][16],
                    u8 *above, u8 *left, u32 predMode, u32 constrainedIntraPred)
{

/* Variables */

    u32 i, comp, block;
    u32 availableA, availableB, availableD;

/* Code */

    ASSERT(data);
    ASSERT(residual);
    ASSERT(above);
    ASSERT(left);
    ASSERT(predMode < 4);

    availableA = h264bsdIsNeighbourAvailable(pMb, pMb->mbA);
    if (availableA && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbA->mbType) == PRED_MODE_INTER))
        availableA = HANTRO_FALSE;
    availableB = h264bsdIsNeighbourAvailable(pMb, pMb->mbB);
    if (availableB && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbB->mbType) == PRED_MODE_INTER))
        availableB = HANTRO_FALSE;
    availableD = h264bsdIsNeighbourAvailable(pMb, pMb->mbD);
    if (availableD && constrainedIntraPred &&
       (h264bsdMbPartPredMode(pMb->mbD->mbType) == PRED_MODE_INTER))
        availableD = HANTRO_FALSE;

    for (comp = 0, block = 16; comp < 2; comp++)
    {
        switch(predMode)
        {
            case 0: /* Intra_Chroma_DC */
                IntraChromaDcPrediction(data, above+1, left, availableA,
                    availableB);
                break;

            case 1: /* Intra_Chroma_Horizontal */
                if (!availableA)
                    return(HANTRO_NOK);
                IntraChromaHorizontalPrediction(data, left);
                break;

            case 2: /* Intra_Chroma_Vertical */
                if (!availableB)
                    return(HANTRO_NOK);
                IntraChromaVerticalPrediction(data, above+1);

                break;

            default: /* case 3: Intra_Chroma_Plane */
                if (!availableA || !availableB || !availableD)
                    return(HANTRO_NOK);
                IntraChromaPlanePrediction(data, above+1, left);
                break;
        }
        for (i = 0; i < 4; i++, block++)
            h264bsdAddResidual(data, residual[i], block);

        /* advance pointers */
        data += 64;
        above += 9;
        left += 8;
        residual += 4;
    }

    return(HANTRO_OK);

}

/*------------------------------------------------------------------------------

    Function: h264bsdAddResidual

        Functional description:
          Add residual of a block into prediction in macroblock array 'data'.
          The result (residual + prediction) is stored in 'data'.

------------------------------------------------------------------------------*/
#ifndef H264DEC_OMXDL
void h264bsdAddResidual(u8 *data, i32 *residual, u32 blockNum)
{

/* Variables */

    u32 i;
    u32 x, y;
    u32 width;
    i32 tmp1, tmp2, tmp3, tmp4;
    u8 *tmp;
    const u8 *clp = h264bsdClip + 512;

/* Code */

    ASSERT(data);
    ASSERT(residual);
    ASSERT(blockNum < 16 + 4 + 4);

    if (IS_RESIDUAL_EMPTY(residual))
        return;

    RANGE_CHECK_ARRAY(residual, -512, 511, 16);

    if (blockNum < 16)
    {
        width = 16;
        x = h264bsdBlockX[blockNum];
        y = h264bsdBlockY[blockNum];
    }
    else
    {
        width = 8;
        x = h264bsdBlockX[blockNum & 0x3];
        y = h264bsdBlockY[blockNum & 0x3];
    }

    tmp = data + y*width + x;
    for (i = 4; i; i--)
    {
        tmp1 = *residual++;
        tmp2 = tmp[0];
        tmp3 = *residual++;
        tmp4 = tmp[1];

        tmp[0] = clp[tmp1 + tmp2];

        tmp1 = *residual++;
        tmp2 = tmp[2];

        tmp[1] = clp[tmp3 + tmp4];

        tmp3 = *residual++;
        tmp4 = tmp[3];

        tmp1 = clp[tmp1 + tmp2];
        tmp3 = clp[tmp3 + tmp4];
        tmp[2] = (u8)tmp1;
        tmp[3] = (u8)tmp3;

        tmp += width;
    }

}
#endif
/*------------------------------------------------------------------------------

    Function: Intra16x16VerticalPrediction

        Functional description:
          Perform intra 16x16 vertical prediction mode.

------------------------------------------------------------------------------*/

void Intra16x16VerticalPrediction(u8 *data, u8 *above)
{

/* Variables */

    u32 i, j;

/* Code */

    ASSERT(data);
    ASSERT(above);

    for (i = 0; i < 16; i++)
    {
        for (j = 0; j < 16; j++)
        {
            *data++ = above[j];
        }
    }

}

/*------------------------------------------------------------------------------

    Function: Intra16x16HorizontalPrediction

        Functional description:
          Perform intra 16x16 horizontal prediction mode.

------------------------------------------------------------------------------*/

void Intra16x16HorizontalPrediction(u8 *data, u8 *left)
{

/* Variables */

    u32 i, j;

/* Code */

    ASSERT(data);
    ASSERT(left);

    for (i = 0; i < 16; i++)
    {
        for (j = 0; j < 16; j++)
        {
            *data++ = left[i];
        }
    }

}

/*------------------------------------------------------------------------------

    Function: Intra16x16DcPrediction

        Functional description:
          Perform intra 16x16 DC prediction mode.

------------------------------------------------------------------------------*/

void Intra16x16DcPrediction(u8 *data, u8 *above, u8 *left, u32 availableA,
    u32 availableB)
{

/* Variables */

    u32 i, tmp;

/* Code */

    ASSERT(data);
    ASSERT(above);
    ASSERT(left);

    if (availableA && availableB)
    {
        for (i = 0, tmp = 0; i < 16; i++)
            tmp += above[i] + left[i];
        tmp = (tmp + 16) >> 5;
    }
    else if (availableA)
    {
        for (i = 0, tmp = 0; i < 16; i++)
            tmp += left[i];
        tmp = (tmp + 8) >> 4;
    }
    else if (availableB)
    {
        for (i = 0, tmp = 0; i < 16; i++)
            tmp += above[i];
        tmp = (tmp + 8) >> 4;
    }
    /* neither A nor B available */
    else
    {
        tmp = 128;
    }
    for (i = 0; i < 256; i++)
        data[i] = (u8)tmp;

}

/*------------------------------------------------------------------------------

    Function: Intra16x16PlanePrediction

        Functional description:
          Perform intra 16x16 plane prediction mode.

------------------------------------------------------------------------------*/

void Intra16x16PlanePrediction(u8 *data, u8 *above, u8 *left)
{

/* Variables */

    i32 i, j;
    i32 a, b, c;
    i32 tmp;

/* Code */

    ASSERT(data);
    ASSERT(above);
    ASSERT(left);

    a = 16 * (above[15] + left[15]);

    for (i = 0, b = 0; i < 8; i++)
        b += (i + 1) * (above[8+i] - above[6-i]);
    b = (5 * b + 32) >> 6;

    for (i = 0, c = 0; i < 7; i++)
        c += (i + 1) * (left[8+i] - left[6-i]);
    /* p[-1,-1] has to be accessed through above pointer */
    c += (i + 1) * (left[8+i] - above[-1]);
    c = (5 * c + 32) >> 6;

    for (i = 0; i < 16; i++)
    {
        for (j = 0; j < 16; j++)
        {
            tmp = (a + b * (j - 7) + c * (i - 7) + 16) >> 5;
            data[i*16+j] = (u8)CLIP1(tmp);
        }
    }

}

/*------------------------------------------------------------------------------

    Function: IntraChromaDcPrediction

        Functional description:
          Perform intra chroma DC prediction mode.

------------------------------------------------------------------------------*/

void IntraChromaDcPrediction(u8 *data, u8 *above, u8 *left, u32 availableA,
    u32 availableB)
{

/* Variables */

    u32 i;
    u32 tmp1, tmp2;

/* Code */

    ASSERT(data);
    ASSERT(above);
    ASSERT(left);

    /* y = 0..3 */
    if (availableA && availableB)
    {
        tmp1 = above[0] + above[1] + above[2] + above[3] +
              left[0] + left[1] + left[2] + left[3];
        tmp1 = (tmp1 + 4) >> 3;
        tmp2 = (above[4] + above[5] + above[6] + above[7] + 2) >> 2;
    }
    else if (availableB)
    {
        tmp1 = (above[0] + above[1] + above[2] + above[3] + 2) >> 2;
        tmp2 = (above[4] + above[5] + above[6] + above[7] + 2) >> 2;
    }
    else if (availableA)
    {
        tmp1 = (left[0] + left[1] + left[2] + left[3] + 2) >> 2;
        tmp2 = tmp1;
    }
    /* neither A nor B available */
    else
    {
        tmp1 = tmp2 = 128;
    }

    ASSERT(tmp1 < 256 && tmp2 < 256);
    for (i = 4; i--;)
    {
        *data++ = (u8)tmp1;
        *data++ = (u8)tmp1;
        *data++ = (u8)tmp1;
        *data++ = (u8)tmp1;
        *data++ = (u8)tmp2;
        *data++ = (u8)tmp2;
        *data++ = (u8)tmp2;
        *data++ = (u8)tmp2;
    }

    /* y = 4...7 */
    if (availableA)
    {
        tmp1 = (left[4] + left[5] + left[6] + left[7] + 2) >> 2;
        if (availableB)
        {
            tmp2 = above[4] + above[5] + above[6] + above[7] +
                   left[4] + left[5] + left[6] + left[7];
            tmp2 = (tmp2 + 4) >> 3;
        }
        else
            tmp2 = tmp1;
    }
    else if (availableB)
    {
        tmp1 = (above[0] + above[1] + above[2] + above[3] + 2) >> 2;
        tmp2 = (above[4] + above[5] + above[6] + above[7] + 2) >> 2;
    }
    else
    {
        tmp1 = tmp2 = 128;
    }

    ASSERT(tmp1 < 256 && tmp2 < 256);
    for (i = 4; i--;)
    {
        *data++ = (u8)tmp1;
        *data++ = (u8)tmp1;
        *data++ = (u8)tmp1;
        *data++ = (u8)tmp1;
        *data++ = (u8)tmp2;
        *data++ = (u8)tmp2;
        *data++ = (u8)tmp2;
        *data++ = (u8)tmp2;
    }
}

/*------------------------------------------------------------------------------

    Function: IntraChromaHorizontalPrediction

        Functional description:
          Perform intra chroma horizontal prediction mode.

------------------------------------------------------------------------------*/

void IntraChromaHorizontalPrediction(u8 *data, u8 *left)
{

/* Variables */

    u32 i;

/* Code */

    ASSERT(data);
    ASSERT(left);

    for (i = 8; i--;)
    {
        *data++ = *left;
        *data++ = *left;
        *data++ = *left;
        *data++ = *left;
        *data++ = *left;
        *data++ = *left;
        *data++ = *left;
        *data++ = *left++;
    }

}

/*------------------------------------------------------------------------------

    Function: IntraChromaVerticalPrediction

        Functional description:
          Perform intra chroma vertical prediction mode.

------------------------------------------------------------------------------*/

void IntraChromaVerticalPrediction(u8 *data, u8 *above)
{

/* Variables */

    u32 i;

/* Code */

    ASSERT(data);
    ASSERT(above);

    for (i = 8; i--;data++/*above-=8*/)
    {
        data[0] = *above;
        data[8] = *above;
        data[16] = *above;
        data[24] = *above;
        data[32] = *above;
        data[40] = *above;
        data[48] = *above;
        data[56] = *above++;
    }

}

/*------------------------------------------------------------------------------

    Function: IntraChromaPlanePrediction

        Functional description:
          Perform intra chroma plane prediction mode.

------------------------------------------------------------------------------*/

void IntraChromaPlanePrediction(u8 *data, u8 *above, u8 *left)
{

/* Variables */

    u32 i;
    i32 a, b, c;
    i32 tmp;
    const u8 *clp = h264bsdClip + 512;

/* Code */

    ASSERT(data);
    ASSERT(above);
    ASSERT(left);

    a = 16 * (above[7] + left[7]);

    b = (above[4] - above[2]) + 2 * (above[5] - above[1])
        + 3 * (above[6] - above[0]) + 4 * (above[7] - above[-1]);
    b = (17 * b + 16) >> 5;

    /* p[-1,-1] has to be accessed through above pointer */
    c = (left[4] - left[2]) + 2 * (left[5] - left[1])
        + 3 * (left[6] - left[0]) + 4 * (left[7] - above[-1]);
    c = (17 * c + 16) >> 5;

    /*a += 16;*/
    a = a - 3 * c + 16;
    for (i = 8; i--; a += c)
    {
        tmp = (a - 3 * b);
        *data++ = clp[tmp>>5];
        tmp += b;
        *data++ = clp[tmp>>5];
        tmp += b;
        *data++ = clp[tmp>>5];
        tmp += b;
        *data++ = clp[tmp>>5];
        tmp += b;
        *data++ = clp[tmp>>5];
        tmp += b;
        *data++ = clp[tmp>>5];
        tmp += b;
        *data++ = clp[tmp>>5];
        tmp += b;
        *data++ = clp[tmp>>5];
    }

}

/*------------------------------------------------------------------------------

    Function: Get4x4NeighbourPels

        Functional description:
          Get neighbouring pixels of a 4x4 block into 'a' and 'l'.

------------------------------------------------------------------------------*/

void Get4x4NeighbourPels(u8 *a, u8 *l, u8 *data, u8 *above, u8 *left,
    u32 blockNum)
{

/* Variables */

    u32 x, y;
    u8 t1, t2;

/* Code */

    ASSERT(a);
    ASSERT(l);
    ASSERT(data);
    ASSERT(above);
    ASSERT(left);
    ASSERT(blockNum < 16);

    x = h264bsdBlockX[blockNum];
    y = h264bsdBlockY[blockNum];

    /* A and D */
    if (x == 0)
    {
        t1 = left[y    ];
        t2 = left[y + 1];
        l[1] = t1;
        l[2] = t2;
        t1 = left[y + 2];
        t2 = left[y + 3];
        l[3] = t1;
        l[4] = t2;
    }
    else
    {
        t1 = data[y * 16 + x - 1     ];
        t2 = data[y * 16 + x - 1 + 16];
        l[1] = t1;
        l[2] = t2;
        t1 = data[y * 16 + x - 1 + 32];
        t2 = data[y * 16 + x - 1 + 48];
        l[3] = t1;
        l[4] = t2;
    }

    /* B, C and D */
    if (y == 0)
    {
        t1 = above[x    ];
        t2 = above[x    ];
        l[0] = t1;
        a[0] = t2;
        t1 = above[x + 1];
        t2 = above[x + 2];
        a[1] = t1;
        a[2] = t2;
        t1 = above[x + 3];
        t2 = above[x + 4];
        a[3] = t1;
        a[4] = t2;
        t1 = above[x + 5];
        t2 = above[x + 6];
        a[5] = t1;
        a[6] = t2;
        t1 = above[x + 7];
        t2 = above[x + 8];
        a[7] = t1;
        a[8] = t2;
    }
    else
    {
        t1 = data[(y - 1) * 16 + x    ];
        t2 = data[(y - 1) * 16 + x + 1];
        a[1] = t1;
        a[2] = t2;
        t1 = data[(y - 1) * 16 + x + 2];
        t2 = data[(y - 1) * 16 + x + 3];
        a[3] = t1;
        a[4] = t2;
        t1 = data[(y - 1) * 16 + x + 4];
        t2 = data[(y - 1) * 16 + x + 5];
        a[5] = t1;
        a[6] = t2;
        t1 = data[(y - 1) * 16 + x + 6];
        t2 = data[(y - 1) * 16 + x + 7];
        a[7] = t1;
        a[8] = t2;

        if (x == 0)
            l[0] = a[0] = left[y-1];
        else
            l[0] = a[0] = data[(y - 1) * 16 + x - 1];
    }
}


/*------------------------------------------------------------------------------

    Function: Intra4x4VerticalPrediction

        Functional description:
          Perform intra 4x4 vertical prediction mode.

------------------------------------------------------------------------------*/

void Intra4x4VerticalPrediction(u8 *data, u8 *above)
{

/* Variables */

    u8 t1, t2;

/* Code */

    ASSERT(data);
    ASSERT(above);

    t1 = above[0];
    t2 = above[1];
    data[0] = data[4] = data[8] = data[12] = t1;
    data[1] = data[5] = data[9] = data[13] = t2;
    t1 = above[2];
    t2 = above[3];
    data[2] = data[6] = data[10] = data[14] = t1;
    data[3] = data[7] = data[11] = data[15] = t2;

}

/*------------------------------------------------------------------------------

    Function: Intra4x4HorizontalPrediction

        Functional description:
          Perform intra 4x4 horizontal prediction mode.

------------------------------------------------------------------------------*/

void Intra4x4HorizontalPrediction(u8 *data, u8 *left)
{

/* Variables */

    u8 t1, t2;

/* Code */

    ASSERT(data);
    ASSERT(left);

    t1 = left[0];
    t2 = left[1];
    data[0] = data[1] = data[2] = data[3] = t1;
    data[4] = data[5] = data[6] = data[7] = t2;
    t1 = left[2];
    t2 = left[3];
    data[8] = data[9] = data[10] = data[11] = t1;
    data[12] = data[13] = data[14] = data[15] = t2;

}

/*------------------------------------------------------------------------------

    Function: Intra4x4DcPrediction

        Functional description:
          Perform intra 4x4 DC prediction mode.

------------------------------------------------------------------------------*/

void Intra4x4DcPrediction(u8 *data, u8 *above, u8 *left, u32 availableA,
    u32 availableB)
{

/* Variables */

    u32 tmp;
    u8 t1, t2, t3, t4;

/* Code */

    ASSERT(data);
    ASSERT(above);
    ASSERT(left);

    if (availableA && availableB)
    {
        t1 = above[0]; t2 = above[1]; t3 = above[2]; t4 = above[3];
        tmp = t1 + t2 + t3 + t4;
        t1 = left[0]; t2 = left[1]; t3 = left[2]; t4 = left[3];
        tmp += t1 + t2 + t3 + t4;
        tmp = (tmp + 4) >> 3;
    }
    else if (availableA)
    {
        t1 = left[0]; t2 = left[1]; t3 = left[2]; t4 = left[3];
        tmp = (t1 + t2 + t3 + t4 + 2) >> 2;
    }
    else if (availableB)
    {
        t1 = above[0]; t2 = above[1]; t3 = above[2]; t4 = above[3];
        tmp = (t1 + t2 + t3 + t4 + 2) >> 2;
    }
    else
    {
        tmp = 128;
    }

    ASSERT(tmp < 256);
    data[0] = data[1] = data[2] = data[3] =
    data[4] = data[5] = data[6] = data[7] =
    data[8] = data[9] = data[10] = data[11] =
    data[12] = data[13] = data[14] = data[15] = (u8)tmp;

}

/*------------------------------------------------------------------------------

    Function: Intra4x4DiagonalDownLeftPrediction

        Functional description:
          Perform intra 4x4 diagonal down-left prediction mode.

------------------------------------------------------------------------------*/

void Intra4x4DiagonalDownLeftPrediction(u8 *data, u8 *above)
{

/* Variables */

/* Code */

    ASSERT(data);
    ASSERT(above);

    data[ 0] = (above[0] + 2 * above[1] + above[2] + 2) >> 2;
    data[ 1] = (above[1] + 2 * above[2] + above[3] + 2) >> 2;
    data[ 4] = (above[1] + 2 * above[2] + above[3] + 2) >> 2;
    data[ 2] = (above[2] + 2 * above[3] + above[4] + 2) >> 2;
    data[ 5] = (above[2] + 2 * above[3] + above[4] + 2) >> 2;
    data[ 8] = (above[2] + 2 * above[3] + above[4] + 2) >> 2;
    data[ 3] = (above[3] + 2 * above[4] + above[5] + 2) >> 2;
    data[ 6] = (above[3] + 2 * above[4] + above[5] + 2) >> 2;
    data[ 9] = (above[3] + 2 * above[4] + above[5] + 2) >> 2;
    data[12] = (above[3] + 2 * above[4] + above[5] + 2) >> 2;
    data[ 7] = (above[4] + 2 * above[5] + above[6] + 2) >> 2;
    data[10] = (above[4] + 2 * above[5] + above[6] + 2) >> 2;
    data[13] = (above[4] + 2 * above[5] + above[6] + 2) >> 2;
    data[11] = (above[5] + 2 * above[6] + above[7] + 2) >> 2;
    data[14] = (above[5] + 2 * above[6] + above[7] + 2) >> 2;
    data[15] = (above[6] + 3 * above[7] + 2) >> 2;

}

/*------------------------------------------------------------------------------

    Function: Intra4x4DiagonalDownRightPrediction

        Functional description:
          Perform intra 4x4 diagonal down-right prediction mode.

------------------------------------------------------------------------------*/

void Intra4x4DiagonalDownRightPrediction(u8 *data, u8 *above, u8 *left)
{

/* Variables */

/* Code */

    ASSERT(data);
    ASSERT(above);
    ASSERT(left);

    data[ 0] = (above[0] + 2 * above[-1] + left[0] + 2) >> 2;
    data[ 5] = (above[0] + 2 * above[-1] + left[0] + 2) >> 2;
    data[10] = (above[0] + 2 * above[-1] + left[0] + 2) >> 2;
    data[15] = (above[0] + 2 * above[-1] + left[0] + 2) >> 2;
    data[ 1] = (above[-1] + 2 * above[0] + above[1] + 2) >> 2;
    data[ 6] = (above[-1] + 2 * above[0] + above[1] + 2) >> 2;
    data[11] = (above[-1] + 2 * above[0] + above[1] + 2) >> 2;
    data[ 2] = (above[0] + 2 * above[1] + above[2] + 2) >> 2;
    data[ 7] = (above[0] + 2 * above[1] + above[2] + 2) >> 2;
    data[ 3] = (above[1] + 2 * above[2] + above[3] + 2) >> 2;
    data[ 4] = (left[-1] + 2 * left[0] + left[1] + 2) >> 2;
    data[ 9] = (left[-1] + 2 * left[0] + left[1] + 2) >> 2;
    data[14] = (left[-1] + 2 * left[0] + left[1] + 2) >> 2;
    data[ 8] = (left[0] + 2 * left[1] + left[2] + 2) >> 2;
    data[13] = (left[0] + 2 * left[1] + left[2] + 2) >> 2;
    data[12] = (left[1] + 2 * left[2] + left[3] + 2) >> 2;
}

/*------------------------------------------------------------------------------

    Function: Intra4x4VerticalRightPrediction

        Functional description:
          Perform intra 4x4 vertical right prediction mode.

------------------------------------------------------------------------------*/

void Intra4x4VerticalRightPrediction(u8 *data, u8 *above, u8 *left)
{

/* Variables */

/* Code */

    ASSERT(data);
    ASSERT(above);
    ASSERT(left);

    data[ 0] = (above[-1] + above[0] + 1) >> 1;
    data[ 9] = (above[-1] + above[0] + 1) >> 1;
    data[ 5] = (above[-1] + 2 * above[0] + above[1] + 2) >> 2;
    data[14] = (above[-1] + 2 * above[0] + above[1] + 2) >> 2;
    data[ 4] = (above[0] + 2 * above[-1] + left[0] + 2) >> 2;
    data[13] = (above[0] + 2 * above[-1] + left[0] + 2) >> 2;
    data[ 1] = (above[0] + above[1] + 1) >> 1;
    data[10] = (above[0] + above[1] + 1) >> 1;
    data[ 6] = (above[0] + 2 * above[1] + above[2] + 2) >> 2;
    data[15] = (above[0] + 2 * above[1] + above[2] + 2) >> 2;
    data[ 2] = (above[1] + above[2] + 1) >> 1;
    data[11] = (above[1] + above[2] + 1) >> 1;
    data[ 7] = (above[1] + 2 * above[2] + above[3] + 2) >> 2;
    data[ 3] = (above[2] + above[3] + 1) >> 1;
    data[ 8] = (left[1] + 2 * left[0] + left[-1] + 2) >> 2;
    data[12] = (left[2] + 2 * left[1] + left[0] + 2) >> 2;

}

/*------------------------------------------------------------------------------

    Function: Intra4x4HorizontalDownPrediction

        Functional description:
          Perform intra 4x4 horizontal down prediction mode.

------------------------------------------------------------------------------*/

void Intra4x4HorizontalDownPrediction(u8 *data, u8 *above, u8 *left)
{

/* Variables */

/* Code */

    ASSERT(data);
    ASSERT(above);
    ASSERT(left);

    data[ 0] = (left[-1] + left[0] + 1) >> 1;
    data[ 6] = (left[-1] + left[0] + 1) >> 1;
    data[ 5] = (left[-1] + 2 * left[0] + left[1] + 2) >> 2;
    data[11] = (left[-1] + 2 * left[0] + left[1] + 2) >> 2;
    data[ 4] = (left[0] + left[1] + 1) >> 1;
    data[10] = (left[0] + left[1] + 1) >> 1;
    data[ 9] = (left[0] + 2 * left[1] + left[2] + 2) >> 2;
    data[15] = (left[0] + 2 * left[1] + left[2] + 2) >> 2;
    data[ 8] = (left[1] + left[2] + 1) >> 1;
    data[14] = (left[1] + left[2] + 1) >> 1;
    data[13] = (left[1] + 2 * left[2] + left[3] + 2) >> 2;
    data[12] = (left[2] + left[3] + 1) >> 1;
    data[ 1] = (above[0] + 2 * above[-1] + left[0] + 2) >> 2;
    data[ 7] = (above[0] + 2 * above[-1] + left[0] + 2) >> 2;
    data[ 2] = (above[1] + 2 * above[0] + above[-1] + 2) >> 2;
    data[ 3] = (above[2] + 2 * above[1] + above[0] + 2) >> 2;
}

/*------------------------------------------------------------------------------

    Function: Intra4x4VerticalLeftPrediction

        Functional description:
          Perform intra 4x4 vertical left prediction mode.

------------------------------------------------------------------------------*/

void Intra4x4VerticalLeftPrediction(u8 *data, u8 *above)
{

/* Variables */

/* Code */

    ASSERT(data);
    ASSERT(above);

    data[ 0] = (above[0] + above[1] + 1) >> 1;
    data[ 1] = (above[1] + above[2] + 1) >> 1;
    data[ 2] = (above[2] + above[3] + 1) >> 1;
    data[ 3] = (above[3] + above[4] + 1) >> 1;
    data[ 4] = (above[0] + 2 * above[1] + above[2] + 2) >> 2;
    data[ 5] = (above[1] + 2 * above[2] + above[3] + 2) >> 2;
    data[ 6] = (above[2] + 2 * above[3] + above[4] + 2) >> 2;
    data[ 7] = (above[3] + 2 * above[4] + above[5] + 2) >> 2;
    data[ 8] = (above[1] + above[2] + 1) >> 1;
    data[ 9] = (above[2] + above[3] + 1) >> 1;
    data[10] = (above[3] + above[4] + 1) >> 1;
    data[11] = (above[4] + above[5] + 1) >> 1;
    data[12] = (above[1] + 2 * above[2] + above[3] + 2) >> 2;
    data[13] = (above[2] + 2 * above[3] + above[4] + 2) >> 2;
    data[14] = (above[3] + 2 * above[4] + above[5] + 2) >> 2;
    data[15] = (above[4] + 2 * above[5] + above[6] + 2) >> 2;

}

/*------------------------------------------------------------------------------

    Function: Intra4x4HorizontalUpPrediction

        Functional description:
          Perform intra 4x4 horizontal up prediction mode.

------------------------------------------------------------------------------*/

void Intra4x4HorizontalUpPrediction(u8 *data, u8 *left)
{

/* Variables */

/* Code */

    ASSERT(data);
    ASSERT(left);

    data[ 0] = (left[0] + left[1] + 1) >> 1;
    data[ 1] = (left[0] + 2 * left[1] + left[2] + 2) >> 2;
    data[ 2] = (left[1] + left[2] + 1) >> 1;
    data[ 3] = (left[1] + 2 * left[2] + left[3] + 2) >> 2;
    data[ 4] = (left[1] + left[2] + 1) >> 1;
    data[ 5] = (left[1] + 2 * left[2] + left[3] + 2) >> 2;
    data[ 6] = (left[2] + left[3] + 1) >> 1;
    data[ 7] = (left[2] + 3 * left[3] + 2) >> 2;
    data[ 8] = (left[2] + left[3] + 1) >> 1;
    data[ 9] = (left[2] + 3 * left[3] + 2) >> 2;
    data[10] = left[3];
    data[11] = left[3];
    data[12] = left[3];
    data[13] = left[3];
    data[14] = left[3];
    data[15] = left[3];

}

#endif /* H264DEC_OMXDL */

/*------------------------------------------------------------------------------

    Function: Write4x4To16x16

        Functional description:
          Write a 4x4 block (data4x4) into correct position
          in 16x16 macroblock (data).

------------------------------------------------------------------------------*/

void Write4x4To16x16(u8 *data, u8 *data4x4, u32 blockNum)
{

/* Variables */

    u32 x, y;
    u32 *in32, *out32;

/* Code */

    ASSERT(data);
    ASSERT(data4x4);
    ASSERT(blockNum < 16);

    x = h264bsdBlockX[blockNum];
    y = h264bsdBlockY[blockNum];

    data += y*16+x;

    ASSERT(((u32)data&0x3) == 0);

    /*lint --e(826) */
    out32 = (u32 *)data;
    /*lint --e(826) */
    in32 = (u32 *)data4x4;

    out32[0] = *in32++;
    out32[4] = *in32++;
    out32[8] = *in32++;
    out32[12] = *in32++;
}

/*------------------------------------------------------------------------------

    Function: DetermineIntra4x4PredMode

        Functional description:
          Returns the intra 4x4 prediction mode of a block based on the
          neighbouring macroblocks and information parsed from stream.

------------------------------------------------------------------------------*/

u32 DetermineIntra4x4PredMode(macroblockLayer_t *pMbLayer,
    u32 available, neighbour_t *nA, neighbour_t *nB, u32 index,
    mbStorage_t *nMbA, mbStorage_t *nMbB)
{

/* Variables */

    u32 mode1, mode2;
    mbStorage_t *pMb;

/* Code */

    ASSERT(pMbLayer);

    /* dc only prediction? */
    if (!available)
        mode1 = 2;
    else
    {
        pMb = nMbA;
        if (h264bsdMbPartPredMode(pMb->mbType) == PRED_MODE_INTRA4x4)
        {
            mode1 = pMb->intra4x4PredMode[nA->index];
        }
        else
            mode1 = 2;

        pMb = nMbB;
        if (h264bsdMbPartPredMode(pMb->mbType) == PRED_MODE_INTRA4x4)
        {
            mode2 = pMb->intra4x4PredMode[nB->index];
        }
        else
            mode2 = 2;

        mode1 = MIN(mode1, mode2);
    }

    if (!pMbLayer->mbPred.prevIntra4x4PredModeFlag[index])
    {
        if (pMbLayer->mbPred.remIntra4x4PredMode[index] < mode1)
        {
            mode1 = pMbLayer->mbPred.remIntra4x4PredMode[index];
        }
        else
        {
            mode1 = pMbLayer->mbPred.remIntra4x4PredMode[index] + 1;
        }
    }

    return(mode1);
}


/*lint +e702 */


