/******************************************************************************
 *
 * Copyright (C) 2015 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.
 *
 *****************************************************************************
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/

/**
*******************************************************************************
* @file
*  ih264_weighted_pred.c
*
* @brief
*  Contains function definitions for weighted prediction functions
*
* @author
*  ittiam
*
* @par List of Functions:
*  - ih264_default_weighted_pred_luma
*  - ih264_default_weighted_pred_chroma
*  - ih264_weighted_pred_luma
*  - ih264_weighted_pred_chroma
*  - ih264_weighted_bipred_luma
*  - ih264_weighted_bipred_chroma
*
* @remarks
*
*******************************************************************************
*/

/*****************************************************************************/
/* File Includes                                                             */
/*****************************************************************************/

/* User Include Files */
#include "ih264_typedefs.h"
#include "ih264_macros.h"
#include "ih264_weighted_pred.h"
#include "ih264_platform_macros.h"


/*****************************************************************************/
/*  Function definitions                                                     */
/*****************************************************************************/

/**
*******************************************************************************
*
* @brief default weighted prediction luma.
*
* @par Description
*  This function performs the default weighted prediction as described in
*  sec 8.4.2.3.1 titled "Default weighted sample prediction process" for luma.
*  The function gets two ht x wd blocks, calculates their rounded-average and
*  stores it in the destination block. (ht,wd) can be (4,4), (8,4), (4,8),
*  (8,8), (16,8), (8,16) or (16,16)
*
* @param[in] pu1_src1
*  Pointer to source 1
*
* @param[in] pu1_src2
*  Pointer to source 2
*
* @param[in] pu1_dst
*  Pointer to destination
*
* @param[in] src_strd1
*  stride for source 1
*
* @param[in] src_strd2
*  stride for source 2
*
* @param[in] dst_strd
*  stride for destination
*
* @param[in] ht
*  height of the block
*
* @param[in] wd
*  width of the block
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
void ih264_default_weighted_pred_luma(UWORD8 *pu1_src1,
                                      UWORD8 *pu1_src2,
                                      UWORD8 *pu1_dst,
                                      WORD32 src_strd1,
                                      WORD32 src_strd2,
                                      WORD32 dst_strd,
                                      WORD32 ht,
                                      WORD32 wd)
{
    WORD32 i, j;

    src_strd1 -= wd;
    src_strd2 -= wd;
    dst_strd -= wd;

    for(i = 0; i < ht; i++)
    {
        for(j = 0; j < wd; j++, pu1_src1++, pu1_src2++, pu1_dst++)
            *pu1_dst = (*pu1_src1 + *pu1_src2 + 1) >> 1;

        pu1_src1 += src_strd1;
        pu1_src2 += src_strd2;
        pu1_dst += dst_strd;
    }
}

/**
*******************************************************************************
*
* @brief default weighted prediction chroma.
*
* @par Description
*  This function performs the default weighted prediction as described in
*  sec 8.4.2.3.1 titled "Default weighted sample prediction process" for chroma.
*  The function gets two ht x wd blocks, calculates their rounded-average and
*  stores it in the destination block. (ht,wd) can be (2,2), (4,2), (2,4),
*  (4,4), (8,4), (4,8) or (8,8).
*
* @param[in] pu1_src1
*  Pointer to source 1
*
* @param[in] pu1_src2
*  Pointer to source 2
*
* @param[in] pu1_dst
*  Pointer to destination
*
* @param[in] src_strd1
*  stride for source 1
*
* @param[in] src_strd2
*  stride for source 2
*
* @param[in] dst_strd
*  stride for destination
*
* @param[in] ht
*  height of the block
*
* @param[in] wd
*  width of the block
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
void ih264_default_weighted_pred_chroma(UWORD8 *pu1_src1,
                                        UWORD8 *pu1_src2,
                                        UWORD8 *pu1_dst,
                                        WORD32 src_strd1,
                                        WORD32 src_strd2,
                                        WORD32 dst_strd,
                                        WORD32 ht,
                                        WORD32 wd)
{
    WORD32 i, j;

    wd = wd << 1;

    src_strd1 -= wd;
    src_strd2 -= wd;
    dst_strd -= wd;

    for(i = 0; i < ht; i++)
    {
        for(j = 0; j < wd; j++, pu1_src1++, pu1_src2++, pu1_dst++)
            *pu1_dst = (*pu1_src1 + *pu1_src2 + 1) >> 1;

        pu1_src1 += src_strd1;
        pu1_src2 += src_strd2;
        pu1_dst += dst_strd;
    }
}

/**
*******************************************************************************
*
* @brief weighted prediction luma.
*
* @par Description
*  This function performs the weighted prediction as described in
*  sec 8.4.2.3.2 titled "weighted sample prediction process" for luma.
*  The function gets one ht x wd block, weights it, rounds it off, offsets it,
*  saturates it to unsigned 8-bit and stores it in the destination block.
*  (ht,wd) can be (4,4), (8,4), (4,8), (8,8), (16,8), (8,16) or (16,16)
*
* @param[in] pu1_src
*  Pointer to source
*
* @param[in] pu1_dst
*  Pointer to destination
*
* @param[in] src_strd
*  stride for source
*
* @param[in] dst_strd
*  stride for destination
*
* @param[in] log_wd
*  number of bits to be rounded off
*
* @param[in] wt
*  weight value
*
* @param[in] ofst
*  offset value
*
* @param[in] ht
*  height of the block
*
* @param[in] wd
*  width of the block
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
void ih264_weighted_pred_luma(UWORD8 *pu1_src,
                              UWORD8 *pu1_dst,
                              WORD32 src_strd,
                              WORD32 dst_strd,
                              WORD32 log_wd,
                              WORD32 wt,
                              WORD32 ofst,
                              WORD32 ht,
                              WORD32 wd)
{
    WORD32 i, j;

    wt = (WORD16)(wt & 0xffff);
    ofst = (WORD8)(ofst & 0xff);

    src_strd -= wd;
    dst_strd -= wd;

    if(log_wd >= 1)
    {
        WORD32 i_ofst = (1 << (log_wd - 1)) + (ofst << log_wd);
        for(i = 0; i < ht; i++)
        {
            for(j = 0; j < wd; j++, pu1_src++, pu1_dst++)
                *pu1_dst = CLIP_U8((wt * (*pu1_src) + i_ofst) >> log_wd);

            pu1_src += src_strd;
            pu1_dst += dst_strd;
        }
    }
    else
    {
        for(i = 0; i < ht; i++)
        {
            for(j = 0; j < wd; j++, pu1_src++, pu1_dst++)
                *pu1_dst = CLIP_U8(wt * (*pu1_src) + ofst);

            pu1_src += src_strd;
            pu1_dst += dst_strd;
        }
    }
}

/**
*******************************************************************************
*
* @brief weighted prediction chroma.
*
* @par Description
*  This function performs the weighted prediction as described in
*  sec 8.4.2.3.2 titled "weighted sample prediction process" for chroma.
*  The function gets one ht x wd block, weights it, rounds it off, offsets it,
*  saturates it to unsigned 8-bit and stores it in the destination block.
*  (ht,wd) can be (2,2), (4,2), (2,4), (4,4), (8,4), (4,8) or (8,8).
*
* @param[in] pu1_src
*  Pointer to source
*
* @param[in] pu1_dst
*  Pointer to destination
*
* @param[in] src_strd
*  stride for source
*
* @param[in] dst_strd
*  stride for destination
*
* @param[in] log_wd
*  number of bits to be rounded off
*
* @param[in] wt
*  weight values for u and v
*
* @param[in] ofst
*  offset values for u and v
*
* @param[in] ht
*  height of the block
*
* @param[in] wd
*  width of the block
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
void ih264_weighted_pred_chroma(UWORD8 *pu1_src,
                                UWORD8 *pu1_dst,
                                WORD32 src_strd,
                                WORD32 dst_strd,
                                WORD32 log_wd,
                                WORD32 wt,
                                WORD32 ofst,
                                WORD32 ht,
                                WORD32 wd)
{
    WORD32 i, j;
    WORD32 wt_u, wt_v;
    WORD32 ofst_u, ofst_v;

    wt_u = (WORD16)(wt & 0xffff);
    wt_v = (WORD16)(wt >> 16);

    ofst_u = (WORD8)(ofst & 0xff);
    ofst_v = (WORD8)(ofst >> 8);

    src_strd -= wd << 1;
    dst_strd -= wd << 1;

    if(log_wd >= 1)
    {
        ofst_u = (1 << (log_wd - 1)) + (ofst_u << log_wd);
        ofst_v = (1 << (log_wd - 1)) + (ofst_v << log_wd);

        for(i = 0; i < ht; i++)
        {
            for(j = 0; j < wd; j++, pu1_src++, pu1_dst++)
            {
                *pu1_dst = CLIP_U8((wt_u * (*pu1_src) + ofst_u) >> log_wd);
                pu1_src++;
                pu1_dst++;
                *pu1_dst = CLIP_U8((wt_v * (*pu1_src) + ofst_v) >> log_wd);
            }
            pu1_src += src_strd;
            pu1_dst += dst_strd;
        }
    }
    else
    {
        for(i = 0; i < ht; i++)
        {
            for(j = 0; j < wd; j++, pu1_src++, pu1_dst++)
            {
                *pu1_dst = CLIP_U8(wt_u * (*pu1_src) + ofst_u);
                pu1_src++;
                pu1_dst++;
                *pu1_dst = CLIP_U8(wt_v * (*pu1_src) + ofst_v);
            }
            pu1_src += src_strd;
            pu1_dst += dst_strd;
        }
    }
}

/**
*******************************************************************************
*
* @brief weighted bi-prediction luma.
*
* @par Description
*  This function performs the weighted biprediction as described in
*  sec 8.4.2.3.2 titled "weighted sample prediction process" for luma.
*  The function gets two ht x wd blocks, weights them, adds them, rounds off
*  the sum, offsets it, saturates it to unsigned 8-bit and stores it in the
*  destination block. (ht,wd) can be (4,4), (8,4), (4,8), (8,8), (16,8), (8,16)
*   or (16,16)
*
* @param[in] pu1_src1
*  Pointer to source 1
*
* @param[in] pu1_src2
*  Pointer to source 2
*
* @param[in] pu1_dst
*  Pointer to destination
*
* @param[in] src_strd1
*  stride for source 1
*
* @param[in] src_strd2
*  stride for source 2
*
* @param[in] dst_strd
*  stride for destination
*
* @param[in] log_wd
*  number of bits to be rounded off
*
* @param[in] wt1
*  weight value for source 1
*
* @param[in] wt2
*  weight value for source 2
*
* @param[in] ofst1
*  offset value for source 1
*
* @param[in] ofst2
*  offset value for source 2
*
* @param[in] ht
*  height of the block
*
* @param[in] wd
*  width of the block
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
void ih264_weighted_bi_pred_luma(UWORD8 *pu1_src1,
                                 UWORD8 *pu1_src2,
                                 UWORD8 *pu1_dst,
                                 WORD32 src_strd1,
                                 WORD32 src_strd2,
                                 WORD32 dst_strd,
                                 WORD32 log_wd,
                                 WORD32 wt1,
                                 WORD32 wt2,
                                 WORD32 ofst1,
                                 WORD32 ofst2,
                                 WORD32 ht,
                                 WORD32 wd)
{
    WORD32 i, j;
    WORD32 shft, ofst;

    ofst1 = (WORD8)(ofst1 & 0xff);
    ofst2 = (WORD8)(ofst2 & 0xff);
    wt1 = (WORD16)(wt1 & 0xffff);
    wt2 = (WORD16)(wt2 & 0xffff);
    ofst = (ofst1 + ofst2 + 1) >> 1;

    shft = log_wd + 1;
    ofst = (1 << log_wd) + (ofst << shft);

    src_strd1 -= wd;
    src_strd2 -= wd;
    dst_strd -= wd;

    for(i = 0; i < ht; i++)
    {
        for(j = 0; j < wd; j++, pu1_src1++, pu1_src2++, pu1_dst++)
            *pu1_dst = CLIP_U8((wt1 * (*pu1_src1) + wt2 * (*pu1_src2) + ofst) >> shft);

        pu1_src1 += src_strd1;
        pu1_src2 += src_strd2;
        pu1_dst += dst_strd;
    }
}

/**
*******************************************************************************
*
* @brief weighted bi-prediction chroma.
*
* @par Description
*  This function performs the weighted biprediction as described in
*  sec 8.4.2.3.2 titled "weighted sample prediction process" for chroma.
*  The function gets two ht x wd blocks, weights them, adds them, rounds off
*  the sum, offsets it, saturates it to unsigned 8-bit and stores it in the
*  destination block. (ht,wd) can be (2,2), (4,2), (2,4), (4,4), (8,4), (4,8)
*  or (8,8)
*
* @param[in] pu1_src1
*  Pointer to source 1
*
* @param[in] pu1_src2
*  Pointer to source 2
*
* @param[in] pu1_dst
*  Pointer to destination
*
* @param[in] src_strd1
*  stride for source 1
*
* @param[in] src_strd2
*  stride for source 2
*
* @param[in] dst_strd
*  stride for destination
*
* @param[in] log_wd
*  number of bits to be rounded off
*
* @param[in] wt1
*  weight value for source 1
*
* @param[in] wt2
*  weight value for source 2
*
* @param[in] ofst1
*  offset value for source 1
*
* @param[in] ofst2
*  offset value for source 2
*
* @param[in] ht
*  height of the block
*
* @param[in] wd
*  width of the block
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
void ih264_weighted_bi_pred_chroma(UWORD8 *pu1_src1,
                                   UWORD8 *pu1_src2,
                                   UWORD8 *pu1_dst,
                                   WORD32 src_strd1,
                                   WORD32 src_strd2,
                                   WORD32 dst_strd,
                                   WORD32 log_wd,
                                   WORD32 wt1,
                                   WORD32 wt2,
                                   WORD32 ofst1,
                                   WORD32 ofst2,
                                   WORD32 ht,
                                   WORD32 wd)
{
    WORD32 i, j;
    WORD32 wt1_u, wt1_v, wt2_u, wt2_v;
    WORD32 ofst1_u, ofst1_v, ofst2_u, ofst2_v;
    WORD32 ofst_u, ofst_v;
    WORD32 shft;

    ofst1_u = (WORD8)(ofst1 & 0xff);
    ofst1_v = (WORD8)(ofst1 >> 8);
    ofst2_u = (WORD8)(ofst2 & 0xff);
    ofst2_v = (WORD8)(ofst2 >> 8);
    wt1_u = (WORD16)(wt1 & 0xffff);
    wt1_v = (WORD16)(wt1 >> 16);
    wt2_u = (WORD16)(wt2 & 0xffff);
    wt2_v = (WORD16)(wt2 >> 16);
    ofst_u = (ofst1_u + ofst2_u + 1) >> 1;
    ofst_v = (ofst1_v + ofst2_v + 1) >> 1;

    src_strd1 -= wd << 1;
    src_strd2 -= wd << 1;
    dst_strd -= wd << 1;

    shft = log_wd + 1;
    ofst_u = (1 << log_wd) + (ofst_u << shft);
    ofst_v = (1 << log_wd) + (ofst_v << shft);

    for(i = 0; i < ht; i++)
    {
        for(j = 0; j < wd; j++, pu1_src1++, pu1_src2++, pu1_dst++)
        {
            *pu1_dst = CLIP_U8((wt1_u * (*pu1_src1) + wt2_u * (*pu1_src2) + ofst_u) >> shft);
            pu1_src1++;
            pu1_src2++;
            pu1_dst++;
            *pu1_dst = CLIP_U8((wt1_v * (*pu1_src1) + wt2_v * (*pu1_src2) + ofst_v) >> shft);
        }
        pu1_src1 += src_strd1;
        pu1_src2 += src_strd2;
        pu1_dst += dst_strd;
    }
}
