/******************************************************************************
 *
 * Copyright (C) 2018 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 ihevce_had_satd.c
*
* @brief
*    This file contains functions of Hadamard SAD and SATD
*
* @author
*    Ittiam
*
* List of Functions
*   <TODO: TO BE ADDED>
*
******************************************************************************
*/

/*****************************************************************************/
/* File Includes                                                             */
/*****************************************************************************/
/* System include files */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>
#include <math.h>

/* User include files */
#include "ihevc_typedefs.h"
#include "itt_video_api.h"
#include "ihevce_api.h"

#include "rc_cntrl_param.h"
#include "rc_frame_info_collector.h"
#include "rc_look_ahead_params.h"

#include "ihevc_defs.h"
#include "ihevc_structs.h"
#include "ihevc_platform_macros.h"
#include "ihevc_deblk.h"
#include "ihevc_itrans_recon.h"
#include "ihevc_chroma_itrans_recon.h"
#include "ihevc_chroma_intra_pred.h"
#include "ihevc_intra_pred.h"
#include "ihevc_inter_pred.h"
#include "ihevc_mem_fns.h"
#include "ihevc_padding.h"
#include "ihevc_weighted_pred.h"
#include "ihevc_sao.h"
#include "ihevc_resi_trans.h"
#include "ihevc_quant_iquant_ssd.h"
#include "ihevc_cabac_tables.h"

#include "ihevce_defs.h"
#include "ihevce_lap_enc_structs.h"
#include "ihevce_multi_thrd_structs.h"
#include "ihevce_multi_thrd_funcs.h"
#include "ihevce_me_common_defs.h"
#include "ihevce_had_satd.h"
#include "ihevce_error_codes.h"
#include "ihevce_bitstream.h"
#include "ihevce_cabac.h"
#include "ihevce_rdoq_macros.h"
#include "ihevce_function_selector.h"
#include "ihevce_enc_structs.h"
#include "ihevce_cmn_utils_instr_set_router.h"
#include "hme_datatype.h"
#include "hme_interface.h"
#include "hme_common_defs.h"
#include "hme_defs.h"

/*****************************************************************************/
/* Function Definitions                                                      */
/*****************************************************************************/

static void ihevce_hadamard_4x4_8bit(
    UWORD8 *pu1_src,
    WORD32 src_strd,
    UWORD8 *pu1_pred,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd)
{
    WORD32 k;
    WORD16 m[16];

    /*===== hadamard horz transform =====*/
    for(k = 0; k < 4; k++)
    {
        WORD32 r0, r1, r2, r3;
        WORD32 h0, h1, h2, h3;

        /* Compute the residue block */
        r0 = pu1_src[0] - pu1_pred[0];
        r1 = pu1_src[1] - pu1_pred[1];
        r2 = pu1_src[2] - pu1_pred[2];
        r3 = pu1_src[3] - pu1_pred[3];

        h0 = r0 + r1;
        h1 = r0 - r1;
        h2 = r2 + r3;
        h3 = r2 - r3;

        m[k * 4 + 0] = h0 + h2;
        m[k * 4 + 1] = h1 + h3;
        m[k * 4 + 2] = h0 - h2;
        m[k * 4 + 3] = h1 - h3;

        pu1_pred += pred_strd;
        pu1_src += src_strd;
    }

    /*===== hadamard vert transform =====*/
    for(k = 0; k < 4; k++)
    {
        WORD32 v0, v1, v2, v3;

        v0 = m[0 + k] + m[4 + k];
        v1 = m[0 + k] - m[4 + k];
        v2 = m[8 + k] + m[12 + k];
        v3 = m[8 + k] - m[12 + k];

        pi2_dst[0 * dst_strd + k] = v0 + v2;
        pi2_dst[1 * dst_strd + k] = v1 + v3;
        pi2_dst[2 * dst_strd + k] = v0 - v2;
        pi2_dst[3 * dst_strd + k] = v1 - v3;
    }
}

static void ihevce_hadamard_8x8_8bit(
    UWORD8 *pu1_src,
    WORD32 src_strd,
    UWORD8 *pu1_pred,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd)
{
    WORD32 i;

    // y0
    ihevce_hadamard_4x4_8bit(pu1_src, src_strd, pu1_pred, pred_strd, pi2_dst, dst_strd);
    // y1
    ihevce_hadamard_4x4_8bit(pu1_src + 4, src_strd, pu1_pred + 4, pred_strd, pi2_dst + 4, dst_strd);
    // y2
    ihevce_hadamard_4x4_8bit(
        pu1_src + 4 * src_strd,
        src_strd,
        pu1_pred + 4 * pred_strd,
        pred_strd,
        pi2_dst + (4 * dst_strd),
        dst_strd);
    // y3
    ihevce_hadamard_4x4_8bit(
        pu1_src + 4 + 4 * src_strd,
        src_strd,
        pu1_pred + 4 + 4 * pred_strd,
        pred_strd,
        pi2_dst + (4 * dst_strd) + 4,
        dst_strd);

    /*   Child HAD results combined as follows to get Parent result */
    /*  _                                                 _         */
    /* |  (y0 + y1) + (y2 + y3)    (y0 - y1) + (y2 - y3)   |        */
    /* |  (y0 + y1) - (y2 + y3)    (y0 - y1) - (y2 - y3)   |        */
    /* \-                                                 -/        */
    for(i = 0; i < 16; i++)
    {
        WORD32 idx = (i >> 2) * dst_strd + (i % 4);
        WORD16 a0 = pi2_dst[idx];
        WORD16 a1 = pi2_dst[4 + idx];
        WORD16 a2 = pi2_dst[(4 * dst_strd) + idx];
        WORD16 a3 = pi2_dst[(4 * dst_strd) + 4 + idx];

        WORD16 b0 = (a0 + a1);
        WORD16 b1 = (a0 - a1);
        WORD16 b2 = (a2 + a3);
        WORD16 b3 = (a2 - a3);

        pi2_dst[idx] = b0 + b2;
        pi2_dst[4 + idx] = b1 + b3;
        pi2_dst[(4 * dst_strd) + idx] = b0 - b2;
        pi2_dst[(4 * dst_strd) + 4 + idx] = b1 - b3;
    }
}

static void ihevce_hadamard_16x16_8bit(
    UWORD8 *pu1_src,
    WORD32 src_strd,
    UWORD8 *pu1_pred,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd)
{
    WORD32 i;

    // y0
    ihevce_hadamard_8x8_8bit(pu1_src, src_strd, pu1_pred, pred_strd, pi2_dst, dst_strd);
    // y1
    ihevce_hadamard_8x8_8bit(pu1_src + 8, src_strd, pu1_pred + 8, pred_strd, pi2_dst + 8, dst_strd);
    // y2
    ihevce_hadamard_8x8_8bit(
        pu1_src + 8 * src_strd,
        src_strd,
        pu1_pred + 8 * pred_strd,
        pred_strd,
        pi2_dst + (8 * dst_strd),
        dst_strd);
    // y3
    ihevce_hadamard_8x8_8bit(
        pu1_src + 8 + 8 * src_strd,
        src_strd,
        pu1_pred + 8 + 8 * pred_strd,
        pred_strd,
        pi2_dst + (8 * dst_strd) + 8,
        dst_strd);

    /*   Child HAD results combined as follows to get Parent result */
    /*  _                                                 _         */
    /* |  (y0 + y1) + (y2 + y3)    (y0 - y1) + (y2 - y3)   |        */
    /* |  (y0 + y1) - (y2 + y3)    (y0 - y1) - (y2 - y3)   |        */
    /* \-                                                 -/        */
    for(i = 0; i < 64; i++)
    {
        WORD32 idx = (i >> 3) * dst_strd + (i % 8);
        WORD16 a0 = pi2_dst[idx];
        WORD16 a1 = pi2_dst[8 + idx];
        WORD16 a2 = pi2_dst[(8 * dst_strd) + idx];
        WORD16 a3 = pi2_dst[(8 * dst_strd) + 8 + idx];

        WORD16 b0 = (a0 + a1) >> 1;
        WORD16 b1 = (a0 - a1) >> 1;
        WORD16 b2 = (a2 + a3) >> 1;
        WORD16 b3 = (a2 - a3) >> 1;

        pi2_dst[idx] = b0 + b2;
        pi2_dst[8 + idx] = b1 + b3;
        pi2_dst[(8 * dst_strd) + idx] = b0 - b2;
        pi2_dst[(8 * dst_strd) + 8 + idx] = b1 - b3;
    }
}

static void ihevce_hadamard_32x32_8bit(
    UWORD8 *pu1_src,
    WORD32 src_strd,
    UWORD8 *pu1_pred,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd)
{
    WORD32 i;

    // y0
    ihevce_hadamard_16x16_8bit(pu1_src, src_strd, pu1_pred, pred_strd, pi2_dst, dst_strd);
    // y1
    ihevce_hadamard_16x16_8bit(
        pu1_src + 16, src_strd, pu1_pred + 16, pred_strd, pi2_dst + 16, dst_strd);
    // y2
    ihevce_hadamard_16x16_8bit(
        pu1_src + 16 * src_strd,
        src_strd,
        pu1_pred + 16 * pred_strd,
        pred_strd,
        pi2_dst + (16 * dst_strd),
        dst_strd);
    // y3
    ihevce_hadamard_16x16_8bit(
        pu1_src + 16 + 16 * src_strd,
        src_strd,
        pu1_pred + 16 + 16 * pred_strd,
        pred_strd,
        pi2_dst + (16 * dst_strd) + 16,
        dst_strd);

    /*   Child HAD results combined as follows to get Parent result */
    /*  _                                                 _         */
    /* |  (y0 + y1) + (y2 + y3)    (y0 - y1) + (y2 - y3)   |        */
    /* |  (y0 + y1) - (y2 + y3)    (y0 - y1) - (y2 - y3)   |        */
    /* \-                                                 -/        */
    for(i = 0; i < 256; i++)
    {
        WORD32 idx = (i >> 4) * dst_strd + (i % 16);
        WORD16 a0 = pi2_dst[idx] >> 2;
        WORD16 a1 = pi2_dst[16 + idx] >> 2;
        WORD16 a2 = pi2_dst[(16 * dst_strd) + idx] >> 2;
        WORD16 a3 = pi2_dst[(16 * dst_strd) + 16 + idx] >> 2;

        WORD16 b0 = (a0 + a1);
        WORD16 b1 = (a0 - a1);
        WORD16 b2 = (a2 + a3);
        WORD16 b3 = (a2 - a3);

        pi2_dst[idx] = b0 + b2;
        pi2_dst[16 + idx] = b1 + b3;
        pi2_dst[(16 * dst_strd) + idx] = b0 - b2;
        pi2_dst[(16 * dst_strd) + 16 + idx] = b1 - b3;
    }
}

/**
*******************************************************************************
*
* @brief
*  Compute Hadamard sad for 4x4 block with 8-bit input
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred_buf
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[in] pi2_dst
*  WORD16 pointer to the transform block
*
* @param[in] dst_strd
*  WORD32 Destination stride
*
* @param[in] size
*  WORD32 transform Block size
*
* @returns hadamard SAD
*
* @remarks
*  Not updating the transform destination now. Only returning the SATD
*
*******************************************************************************
*/
UWORD32 ihevce_HAD_4x4_8bit(
    UWORD8 *pu1_origin,
    WORD32 src_strd,
    UWORD8 *pu1_pred_buf,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd)
{
    WORD32 k;
    WORD16 v[16];
    UWORD32 u4_sad = 0;

    (void)pi2_dst;
    (void)dst_strd;
    ihevce_hadamard_4x4_8bit(pu1_origin, src_strd, pu1_pred_buf, pred_strd, v, 4);

    for(k = 0; k < 16; ++k)
        u4_sad += abs(v[k]);
    u4_sad = ((u4_sad + 2) >> 2);

    return u4_sad;
}

/**
*******************************************************************************
*
* @brief
*  Computes Hadamard Sad for 8x8 block with 8-bit input
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred_buf
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[in] pi2_dst
*  WORD16 pointer to the transform block
*
* @param[in] dst_strd
*  WORD32 Destination stride
*
* @param[in] size
*  WORD32 transform Block size
*
* @returns Hadamard SAD
*
* @remarks
*  Not updating the transform destination now. Only returning the SATD
*
*******************************************************************************
*/
UWORD32 ihevce_HAD_8x8_8bit(
    UWORD8 *pu1_origin,
    WORD32 src_strd,
    UWORD8 *pu1_pred_buf,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd)
{
    WORD32 k;
    UWORD32 u4_sad = 0;
    WORD16 v[64];

    (void)pi2_dst;
    (void)dst_strd;
    ihevce_hadamard_8x8_8bit(pu1_origin, src_strd, pu1_pred_buf, pred_strd, v, 8);

    for(k = 0; k < 64; ++k)
        u4_sad += abs(v[k]);
    u4_sad = ((u4_sad + 4) >> 3);

    return u4_sad;
}

/**
*******************************************************************************
*
* @brief
*  Compute dc suppressed hadamard sad for 8x8 block with 8-bit input
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred_buf
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[in] pi2_dst
*  WORD16 pointer to the transform block
*
* @param[in] dst_strd
*  WORD32 Destination stride
*
* @param[in] size
*  WORD32 transform Block size
*
* @returns Hadamard SAD with DC Suppressed
*
* @remarks
*  Not updating the transform destination now. Only returning the SATD
*
*******************************************************************************
*/
UWORD32 ihevce_compute_ac_had_8x8_8bit(
    UWORD8 *pu1_origin,
    WORD32 src_strd,
    UWORD8 *pu1_pred_buf,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd)
{
    WORD32 k;
    UWORD32 u4_sad = 0;
    WORD16 v[64];

    (void)pi2_dst;
    (void)dst_strd;
    ihevce_hadamard_8x8_8bit(pu1_origin, src_strd, pu1_pred_buf, pred_strd, v, 8);

    v[0] = 0;
    for(k = 0; k < 64; ++k)
        u4_sad += abs(v[k]);
    u4_sad = ((u4_sad + 4) >> 3);

    return u4_sad;
}

/**
*******************************************************************************
*
* @brief
*  Computes Hadamard Sad for 16x16 block with 8-bit input
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred_buf
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[in] pi2_dst
*  WORD16 pointer to the transform block
*
* @param[in] dst_strd
*  WORD32 Destination stride
*
* @param[in] size
*  WORD32 transform Block size
*
* @returns Hadamard SAD
*
* @remarks
*  Not updating the transform destination now. Only returning the SATD
*
*******************************************************************************
*/
UWORD32 ihevce_HAD_16x16_8bit(
    UWORD8 *pu1_origin,
    WORD32 src_strd,
    UWORD8 *pu1_pred_buf,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd)
{
    WORD32 k;
    UWORD32 u4_sad = 0;
    WORD16 v[256];

    (void)pi2_dst;
    (void)dst_strd;
    ihevce_hadamard_16x16_8bit(pu1_origin, src_strd, pu1_pred_buf, pred_strd, v, 16);

    for(k = 0; k < 256; ++k)
        u4_sad += abs(v[k]);
    u4_sad = ((u4_sad + 4) >> 3);

    return u4_sad;
}

/**
*******************************************************************************
*
* @brief
*  Computes Hadamard Sad for 32x32 block with 8-bit input
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred_buf
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[in] pi2_dst
*  WORD16 pointer to the transform block
*
* @param[in] dst_strd
*  WORD32 Destination stride
*
* @param[in] size
*  WORD32 transform Block size
*
* @returns Hadamard SAD
*
* @remarks
*  Not updating the transform destination now. Only returning the SATD
*
*******************************************************************************
*/
UWORD32 ihevce_HAD_32x32_8bit(
    UWORD8 *pu1_origin,
    WORD32 src_strd,
    UWORD8 *pu1_pred_buf,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd)
{
    WORD32 k;
    UWORD32 u4_sad = 0;
    WORD16 v[32 * 32];

    (void)pi2_dst;
    (void)dst_strd;
    ihevce_hadamard_32x32_8bit(pu1_origin, src_strd, pu1_pred_buf, pred_strd, v, 32);

    for(k = 0; k < 32 * 32; ++k)
        u4_sad += abs(v[k]);
    u4_sad = ((u4_sad + 2) >> 2);

    return u4_sad;
}

//#if COMPUTE_16x16_R == C
/**
*******************************************************************************
*
* @brief
*   Computes 8x8 transform using children 4x4 hadamard results
*
* @par Description:
*
* @param[in] pi2_4x4_had
*  WORD16 pointer to 4x4 hadamard buffer(y0, y1, y2, y3 hadmard in Zscan order)
*
* @param[in] had4_strd
*  stride of 4x4 hadmard buffer pi2_y0, pi2_y1, pi2_y2, pi2_y3
*
* @param[out] pi2_dst
*  destination buffer where 8x8 hadamard result is stored
*
* @param[in] dst_stride
*  stride of destination block
*
* @param[in] i4_frm_qstep
*  frm_qstep value based on the which the threshold value is calculated
*
* @returns
*  8x8 Hadamard SATD
* @remarks
*
*******************************************************************************
*/
static UWORD32 ihevce_compute_8x8HAD_using_4x4(
    WORD16 *pi2_4x4_had,
    WORD32 had4_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd,
    WORD32 i4_frm_qstep,
    WORD32 *pi4_cbf)
{
    /* Qstep value is right shifted by 8 */
    WORD32 threshold = (i4_frm_qstep >> 8);

    /* Initialize pointers to 4 subblocks of 4x4 HAD buffer */
    WORD16 *pi2_y0 = pi2_4x4_had;
    WORD16 *pi2_y1 = pi2_4x4_had + 4;
    WORD16 *pi2_y2 = pi2_4x4_had + had4_strd * 4;
    WORD16 *pi2_y3 = pi2_4x4_had + had4_strd * 4 + 4;

    /* Initialize pointers to store 8x8 HAD output */
    WORD16 *pi2_dst0 = pi2_dst;
    WORD16 *pi2_dst1 = pi2_dst + 4;
    WORD16 *pi2_dst2 = pi2_dst + dst_strd * 4;
    WORD16 *pi2_dst3 = pi2_dst + dst_strd * 4 + 4;

    UWORD32 u4_satd = 0;
    WORD32 i;

    /*   Child HAD results combined as follows to get Parent result */
    /*  _                                                 _         */
    /* |  (y0 + y1) + (y2 + y3)    (y0 - y1) + (y2 - y3)   |        */
    /* |  (y0 + y1) - (y2 + y3)    (y0 - y1) - (y2 - y3)   |        */
    /* \-                                                 -/        */
    for(i = 0; i < 16; i++)
    {
        WORD32 src_idx = (i >> 2) * had4_strd + (i % 4);
        WORD32 dst_idx = (i >> 2) * dst_strd + (i % 4);

        WORD16 a0 = pi2_y0[src_idx];
        WORD16 a1 = pi2_y1[src_idx];
        WORD16 a2 = pi2_y2[src_idx];
        WORD16 a3 = pi2_y3[src_idx];

        WORD16 b0 = (a0 + a1);
        WORD16 b1 = (a0 - a1);
        WORD16 b2 = (a2 + a3);
        WORD16 b3 = (a2 - a3);

        pi2_dst0[dst_idx] = b0 + b2;
        pi2_dst1[dst_idx] = b1 + b3;
        pi2_dst2[dst_idx] = b0 - b2;
        pi2_dst3[dst_idx] = b1 - b3;

        if(ABS(pi2_dst0[dst_idx]) > threshold)
            *pi4_cbf = 1;
        if(ABS(pi2_dst1[dst_idx]) > threshold)
            *pi4_cbf = 1;
        if(ABS(pi2_dst2[dst_idx]) > threshold)
            *pi4_cbf = 1;
        if(ABS(pi2_dst3[dst_idx]) > threshold)
            *pi4_cbf = 1;

        u4_satd += ABS(pi2_dst0[dst_idx]);
        u4_satd += ABS(pi2_dst1[dst_idx]);
        u4_satd += ABS(pi2_dst2[dst_idx]);
        u4_satd += ABS(pi2_dst3[dst_idx]);
    }

    /* return the 8x8 satd */
    return (u4_satd);
}

/**
*******************************************************************************
*
* @brief
*    Computes Residue and Hadamard Transform for four 4x4 blocks (Z scan) of
*    a 8x8 block (Residue is computed for 8-bit src and prediction buffers)
*    Modified to incorporate the dead-zone implementation - Lokesh
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[out] pi2_dst
*  WORD16 pointer to the transform block
*
* @param[in] dst_strd
*  WORD32 Destination stride
*
* @param[out] pi4_hsad
*  array for storing hadmard sad of each 4x4 block
*
* @param[in] hsad_stride
*  stride of hadmard sad destination buffer (for Zscan order of storing sads)
*
* @param[in] i4_frm_qstep
*  frm_qstep value based on the which the threshold value is calculated
*
* @returns
*
* @remarks
*
*******************************************************************************
*/
static WORD32 ihevce_had4_4x4(
    UWORD8 *pu1_src,
    WORD32 src_strd,
    UWORD8 *pu1_pred,
    WORD32 pred_strd,
    WORD16 *pi2_dst4x4,
    WORD32 dst_strd,
    WORD32 *pi4_hsad,
    WORD32 hsad_stride,
    WORD32 i4_frm_qstep)
{
    WORD32 i, k;
    WORD32 i4_child_total_sad = 0;

    (void)i4_frm_qstep;
    /* -------- Compute four 4x4 HAD Transforms ---------*/
    for(i = 0; i < 4; i++)
    {
        UWORD8 *pu1_pi0, *pu1_pi1;
        WORD16 *pi2_dst;
        WORD32 blkx, blky;
        UWORD32 u4_hsad = 0;
        // TODO: choose deadzone as f(qstep)
        WORD32 threshold = 0;

        /*****************************************************/
        /*    Assuming the looping structure of the four     */
        /*    blocks is in Z scan order of 4x4s in a 8x8     */
        /*    block instead of raster scan                   */
        /*****************************************************/
        blkx = (i & 0x1);
        blky = (i >> 1);

        pu1_pi0 = pu1_src + (blkx * 4) + (blky * 4 * src_strd);
        pu1_pi1 = pu1_pred + (blkx * 4) + (blky * 4 * pred_strd);
        pi2_dst = pi2_dst4x4 + (blkx * 4) + (blky * 4 * dst_strd);

        ihevce_hadamard_4x4_8bit(pu1_pi0, src_strd, pu1_pi1, pred_strd, pi2_dst, dst_strd);

        for(k = 0; k < 4; k++)
        {
            if(ABS(pi2_dst[0 * dst_strd + k]) < threshold)
                pi2_dst[0 * dst_strd + k] = 0;

            if(ABS(pi2_dst[1 * dst_strd + k]) < threshold)
                pi2_dst[1 * dst_strd + k] = 0;

            if(ABS(pi2_dst[2 * dst_strd + k]) < threshold)
                pi2_dst[2 * dst_strd + k] = 0;

            if(ABS(pi2_dst[3 * dst_strd + k]) < threshold)
                pi2_dst[3 * dst_strd + k] = 0;

            /* Accumulate the SATD */
            u4_hsad += ABS(pi2_dst[0 * dst_strd + k]);
            u4_hsad += ABS(pi2_dst[1 * dst_strd + k]);
            u4_hsad += ABS(pi2_dst[2 * dst_strd + k]);
            u4_hsad += ABS(pi2_dst[3 * dst_strd + k]);
        }

        /*===== Normalize the HSAD =====*/
        pi4_hsad[blkx + (blky * hsad_stride)] = ((u4_hsad + 2) >> 2);
        i4_child_total_sad += ((u4_hsad + 2) >> 2);
    }
    return i4_child_total_sad;
}

/**
*******************************************************************************
*
* @brief
*    HSAD is returned for the 4, 4x4 in 8x8
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[out] pi2_dst
*  WORD16 pointer to the transform output block
*
* @param[out] dst_strd
*  WORD32 Destination stride
*
* @param[out] ppi4_hsad
*   pointer to base pointers for storing hadmard sads of various
*   block sizes (4x4 to 32x32)
*
* @param[in] pos_x_y_4x4
*   Denotes packed x,y postion of current 4x4 block w.r.t to start of ctb/CU/MB
*   Lower 16bits denote xpos and upper 16ypos of the 4x4block
*
* @param[in] num_4x4_in_row
*   Denotes the number of current 4x4 blocks in a ctb/CU/MB
*
* @returns
*
* @remarks
*
*******************************************************************************
*/
void ihevce_had_8x8_using_4_4x4(
    UWORD8 *pu1_src,
    WORD32 src_strd,
    UWORD8 *pu1_pred,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd,
    WORD32 **ppi4_hsad,
    WORD32 pos_x_y_4x4,
    WORD32 num_4x4_in_row)
{
    WORD16 ai2_4x4_had[64];
    WORD32 pos_x = pos_x_y_4x4 & 0xFFFF;
    WORD32 pos_y = (pos_x_y_4x4 >> 16) & 0xFFFF;
    WORD32 *pi4_4x4_hsad;
    WORD32 *pi4_8x8_hsad;

    (void)pi2_dst;
    (void)dst_strd;
    ASSERT(pos_x >= 0);
    ASSERT(pos_y >= 0);

    /* Initialize pointers to  store 4x4 and 8x8 HAD SATDs */
    pi4_4x4_hsad = ppi4_hsad[HAD_4x4] + pos_x + pos_y * num_4x4_in_row;
    pi4_8x8_hsad = ppi4_hsad[HAD_8x8] + (pos_x >> 1) + (pos_y >> 1) * (num_4x4_in_row >> 1);

    /* -------- Compute four 4x4 HAD Transforms of 8x8 in one call--------- */
    pi4_8x8_hsad[0] = ihevce_had4_4x4(
        pu1_src, src_strd, pu1_pred, pred_strd, ai2_4x4_had, 8, pi4_4x4_hsad, num_4x4_in_row, 0);
}

/**
*******************************************************************************
*
* @brief
*    Reursive Hadamard Transform for 8x8 block. HSAD is returned for the 8x8
*    block and its four subblocks(4x4).
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[out] pi2_dst
*  WORD16 pointer to the transform output block
*
* @param[out] dst_strd
*  WORD32 Destination stride
*
* @param[out] ppi4_hsad
*   pointer to base pointers for storing hadmard sads of various
*   block sizes (4x4 to 32x32)
*
* @param[in] pos_x_y_4x4
*   Denotes packed x,y postion of current 4x4 block w.r.t to start of ctb/CU/MB
*   Lower 16bits denote xpos and upper 16ypos of the 4x4block
*
* @param[in] num_4x4_in_row
*   Denotes the number of current 4x4 blocks in a ctb/CU/MB
*
* @param[in] i4_frm_qstep
*  frm_qstep value based on the which the threshold value is calculated
*
* @returns
*
* @remarks
*
*******************************************************************************
*/
WORD32 ihevce_had_8x8_using_4_4x4_r(
    UWORD8 *pu1_src,
    WORD32 src_strd,
    UWORD8 *pu1_pred,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd,
    WORD32 **ppi4_hsad,
    WORD32 **ppi4_tu_split,
    WORD32 **ppi4_tu_early_cbf,
    WORD32 pos_x_y_4x4,
    WORD32 num_4x4_in_row,
    WORD32 lambda,
    WORD32 lambda_q_shift,
    WORD32 i4_frm_qstep,
    WORD32 i4_cur_depth,
    WORD32 i4_max_depth,
    WORD32 i4_max_tr_size,
    WORD32 *pi4_tu_split_cost,
    void *pv_func_sel)
{
    WORD16 ai2_4x4_had[64];
    WORD32 pos_x = pos_x_y_4x4 & 0xFFFF;
    WORD32 pos_y = (pos_x_y_4x4 >> 16) & 0xFFFF;
    WORD32 *pi4_4x4_hsad;
    WORD32 *pi4_8x8_hsad;
    WORD32 *pi4_8x8_tu_split;

    WORD32 *pi4_8x8_tu_early_cbf;

    UWORD32 u4_satd;
    WORD32 cost_child = 0, cost_parent = 0;
    WORD32 early_cbf = 0;

    const UWORD8 u1_cur_tr_size = 8;
    /* Stores the best cost for the Current 8x8: Lokesh */
    WORD32 best_cost = 0;

    (void)pv_func_sel;
    ASSERT(pos_x >= 0);
    ASSERT(pos_y >= 0);

    /* Initialize pointers to  store 4x4 and 8x8 HAD SATDs */
    pi4_4x4_hsad = ppi4_hsad[HAD_4x4] + pos_x + pos_y * num_4x4_in_row;
    pi4_8x8_hsad = ppi4_hsad[HAD_8x8] + (pos_x >> 1) + (pos_y >> 1) * (num_4x4_in_row >> 1);
    pi4_8x8_tu_split = ppi4_tu_split[HAD_8x8] + (pos_x >> 1) + (pos_y >> 1) * (num_4x4_in_row >> 1);
    pi4_8x8_tu_early_cbf =
        ppi4_tu_early_cbf[HAD_8x8] + (pos_x >> 1) + (pos_y >> 1) * (num_4x4_in_row >> 1);

    /* -------- Compute four 4x4 HAD Transforms of 8x8 in one call--------- */
    cost_child = ihevce_had4_4x4(
        pu1_src, src_strd, pu1_pred, pred_strd, ai2_4x4_had, 8, pi4_4x4_hsad, num_4x4_in_row, 0);

    /* -------- Compute 8x8 HAD Transform using 4x4 results ------------- */
    u4_satd = ihevce_compute_8x8HAD_using_4x4(
        ai2_4x4_had, 8, pi2_dst, dst_strd, i4_frm_qstep, &early_cbf);

    /* store the normalized 8x8 satd */
    cost_parent = ((u4_satd + 4) >> 3);

    /* 4 CBF Flags, extra 1 becoz of the 0.5 bits per bin is assumed */
    cost_child += ((4) * lambda) >> (lambda_q_shift + 1);

    if(i4_cur_depth < i4_max_depth)
    {
        if((cost_child < cost_parent) || (i4_max_tr_size < u1_cur_tr_size))
        {
            //cost_child -= ((4) * lambda) >> (lambda_q_shift + 1);
            *pi4_tu_split_cost += (4 * lambda) >> (lambda_q_shift + 1);
            best_cost = cost_child;
            best_cost <<= 1;
            best_cost++;
            pi4_8x8_tu_split[0] = 1;
            pi4_8x8_hsad[0] = cost_child;
        }
        else
        {
            //cost_parent -= ((1) * lambda) >>  (lambda_q_shift + 1);
            best_cost = cost_parent;
            best_cost <<= 1;
            pi4_8x8_tu_split[0] = 0;
            pi4_8x8_hsad[0] = cost_parent;
        }
    }
    else
    {
        //cost_parent -= ((1) * lambda) >>  (lambda_q_shift + 1);
        best_cost = cost_parent;
        best_cost <<= 1;
        pi4_8x8_tu_split[0] = 0;
        pi4_8x8_hsad[0] = cost_parent;
    }

    pi4_8x8_tu_early_cbf[0] = early_cbf;

    /* best cost has tu_split_flag at LSB(Least significant bit) */
    return ((best_cost << 1) + early_cbf);
}

/**
*******************************************************************************
*
* @brief
*   Computes 16x16 transform using children 8x8 hadamard results
*    Modified to incorporate the dead-zone implementation - Lokesh
*
* @par Description:
*
* @param[in] pi2_8x8_had
*  WORD16 pointer to 8x8 hadamard buffer(y0, y1, y2, y3 hadmard in Zscan order)
*
* @param[in] had8_strd
*  stride of 8x8 hadmard buffer pi2_y0, pi2_y1, pi2_y2, pi2_y3
*
* @param[out] pi2_dst
*  destination buffer where 8x8 hadamard result is stored
*
* @param[in] dst_stride
*  stride of destination block
*
* @param[in] i4_frm_qstep
*  frm_qstep value based on the which the threshold value is calculated
*
* @returns
*  16x16 Hadamard SATD
* @remarks
*
*******************************************************************************
*/
static UWORD32 ihevce_compute_16x16HAD_using_8x8(
    WORD16 *pi2_8x8_had,
    WORD32 had8_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd,
    WORD32 i4_frm_qstep,
    WORD32 *pi4_cbf)
{
    /* Qstep value is right shifted by 8 */
    WORD32 threshold = (i4_frm_qstep >> 8);

    /* Initialize pointers to 4 subblocks of 8x8 HAD buffer */
    WORD16 *pi2_y0 = pi2_8x8_had;
    WORD16 *pi2_y1 = pi2_8x8_had + 8;
    WORD16 *pi2_y2 = pi2_8x8_had + had8_strd * 8;
    WORD16 *pi2_y3 = pi2_8x8_had + had8_strd * 8 + 8;

    /* Initialize pointers to store 8x8 HAD output */
    WORD16 *pi2_dst0 = pi2_dst;
    WORD16 *pi2_dst1 = pi2_dst + 8;
    WORD16 *pi2_dst2 = pi2_dst + dst_strd * 8;
    WORD16 *pi2_dst3 = pi2_dst + dst_strd * 8 + 8;

    UWORD32 u4_satd = 0;
    WORD32 i;

    /*   Child HAD results combined as follows to get Parent result */
    /*  _                                                 _         */
    /* |  (y0 + y1) + (y2 + y3)    (y0 - y1) + (y2 - y3)   |        */
    /* |  (y0 + y1) - (y2 + y3)    (y0 - y1) - (y2 - y3)   |        */
    /* \-                                                 -/        */
    for(i = 0; i < 64; i++)
    {
        WORD32 src_idx = (i >> 3) * had8_strd + (i % 8);
        WORD32 dst_idx = (i >> 3) * dst_strd + (i % 8);

        WORD16 a0 = pi2_y0[src_idx];
        WORD16 a1 = pi2_y1[src_idx];
        WORD16 a2 = pi2_y2[src_idx];
        WORD16 a3 = pi2_y3[src_idx];

        WORD16 b0 = (a0 + a1) >> 1;
        WORD16 b1 = (a0 - a1) >> 1;
        WORD16 b2 = (a2 + a3) >> 1;
        WORD16 b3 = (a2 - a3) >> 1;

        pi2_dst0[dst_idx] = b0 + b2;
        pi2_dst1[dst_idx] = b1 + b3;
        pi2_dst2[dst_idx] = b0 - b2;
        pi2_dst3[dst_idx] = b1 - b3;

        /* Make the value of dst to zerp, if it falls below the dead-zone */
        if(ABS(pi2_dst0[dst_idx]) > threshold)
            *pi4_cbf = 1;
        if(ABS(pi2_dst1[dst_idx]) > threshold)
            *pi4_cbf = 1;
        if(ABS(pi2_dst2[dst_idx]) > threshold)
            *pi4_cbf = 1;
        if(ABS(pi2_dst3[dst_idx]) > threshold)
            *pi4_cbf = 1;

        u4_satd += ABS(pi2_dst0[dst_idx]);
        u4_satd += ABS(pi2_dst1[dst_idx]);
        u4_satd += ABS(pi2_dst2[dst_idx]);
        u4_satd += ABS(pi2_dst3[dst_idx]);
    }

    /* return 16x16 satd */
    return (u4_satd);
}

/**
*******************************************************************************
*
* @brief
*    Hadamard Transform for 16x16 block with 8x8 and 4x4 SATD updates.
*    Uses recursive 8x8 had output to compute satd for 16x16 and its children
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[out] pi2_dst
*  WORD16 pointer to the transform output block
*
* @param[out] dst_strd
*  WORD32 Destination stride
*
* @param[out] ppi4_hsad
*   pointer to base pointers for storing hadmard sads of various
*   block sizes (4x4 to 32x32)
*
* @param[in] pos_x_y_4x4
*   Denotes packed x,y postion of current 4x4 block w.r.t to start of ctb/CU/MB
*   Lower 16bits denote xpos and upper 16ypos of the 4x4block
*
* @param[in] num_4x4_in_row
*   Denotes the number of current 4x4 blocks in a ctb/CU/MB
*
* @param[in] lambda
*  lambda values is the cost factor calculated based on QP
*
* @param[in] lambda_q_shift
*  lambda_q_shift used to reverse the lambda value back from q8 format
*
* @param[in] depth
*  depth gives the current TU depth with respect to the CU
*
* @param[in] i4_frm_qstep
*  frm_qstep value based on the which the threshold value is calculated
*
* @returns
*
* @remarks
*
*******************************************************************************
*/

WORD32 ihevce_had_16x16_r(
    UWORD8 *pu1_src,
    WORD32 src_strd,
    UWORD8 *pu1_pred,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd,
    WORD32 **ppi4_hsad,
    WORD32 **ppi4_tu_split,
    WORD32 **ppi4_tu_early_cbf,
    WORD32 pos_x_y_4x4,
    WORD32 num_4x4_in_row,
    WORD32 lambda,
    WORD32 lambda_q_shift,
    WORD32 i4_frm_qstep,
    WORD32 i4_cur_depth,
    WORD32 i4_max_depth,
    WORD32 i4_max_tr_size,
    WORD32 *pi4_tu_split_cost,
    void *pv_func_sel)
{
    WORD16 ai2_8x8_had[256];
    WORD32 *pi4_16x16_hsad;
    WORD32 *pi4_16x16_tu_split;

    WORD32 *pi4_16x16_tu_early_cbf;

    UWORD32 u4_satd = 0;
    WORD32 tu_split_flag = 0;
    WORD32 i4_early_cbf_flag = 0, early_cbf = 0;
    const UWORD8 u1_cur_tr_size = 16;

    /* cost_parent : Stores the cost of the parent HAD transform (16x16) */
    /* cost_child : Stores the cost of the child HAD transform (16x16) */
    WORD32 cost_parent = 0, cost_child = 0;

    /*best_cost returns the best cost at the end of the function */
    /*tu_split denoes whether the TU (16x16)is split or not */
    WORD32 best_cost = 0, best_cost_tu_split;
    WORD32 i;

    WORD16 *pi2_y0;
    UWORD8 *pu1_src0;
    UWORD8 *pu1_pred0;
    WORD32 pos_x_y_4x4_0;

    WORD32 pos_x = pos_x_y_4x4 & 0xFFFF;
    WORD32 pos_y = (pos_x_y_4x4 >> 16) & 0xFFFF;

    ASSERT(pos_x >= 0);
    ASSERT(pos_y >= 0);

    /* Initialize pointers to  store 16x16 SATDs */
    pi4_16x16_hsad = ppi4_hsad[HAD_16x16] + (pos_x >> 2) + (pos_y >> 2) * (num_4x4_in_row >> 2);

    pi4_16x16_tu_split =
        ppi4_tu_split[HAD_16x16] + (pos_x >> 2) + (pos_y >> 2) * (num_4x4_in_row >> 2);

    pi4_16x16_tu_early_cbf =
        ppi4_tu_early_cbf[HAD_16x16] + (pos_x >> 2) + (pos_y >> 2) * (num_4x4_in_row >> 2);

    /* -------- Compute four 8x8 HAD Transforms of 16x16 call--------- */
    for(i = 0; i < 4; i++)
    {
        pu1_src0 = pu1_src + (i & 0x01) * 8 + (i >> 1) * src_strd * 8;
        pu1_pred0 = pu1_pred + (i & 0x01) * 8 + (i >> 1) * pred_strd * 8;
        pi2_y0 = ai2_8x8_had + (i & 0x01) * 8 + (i >> 1) * 16 * 8;
        pos_x_y_4x4_0 = pos_x_y_4x4 + (i & 0x01) * 2 + (i >> 1) * (2 << 16);

        best_cost_tu_split = ihevce_had_8x8_using_4_4x4_r(
            pu1_src0,
            src_strd,
            pu1_pred0,
            pred_strd,
            pi2_y0,
            16,
            ppi4_hsad,
            ppi4_tu_split,
            ppi4_tu_early_cbf,
            pos_x_y_4x4_0,
            num_4x4_in_row,
            lambda,
            lambda_q_shift,
            i4_frm_qstep,
            i4_cur_depth + 1,
            i4_max_depth,
            i4_max_tr_size,
            pi4_tu_split_cost,
            pv_func_sel);

        /* Cost is shifted by two bits for Tu_split_flag and early cbf flag */
        best_cost = (best_cost_tu_split >> 2);

        /* Last but one bit stores the information regarding the TU_Split */
        tu_split_flag += (best_cost_tu_split & 0x3) >> 1;

        /* Last bit stores the information regarding the early_cbf */
        i4_early_cbf_flag += (best_cost_tu_split & 0x1);

        cost_child += best_cost;

        tu_split_flag <<= 1;
        i4_early_cbf_flag <<= 1;
    }

    /* -------- Compute 16x16 HAD Transform using 8x8 results ------------- */
    pi2_y0 = ai2_8x8_had;

    /* Threshold currently passed as "0" */
    u4_satd =
        ihevce_compute_16x16HAD_using_8x8(pi2_y0, 16, pi2_dst, dst_strd, i4_frm_qstep, &early_cbf);

    /* store the normalized satd */
    cost_parent = ((u4_satd + 4) >> 3);

    /* 4 TU_Split flags , 4 CBF Flags, extra 1 becoz of the 0.5 bits per bin is assumed */
    cost_child += ((4 + 4) * lambda) >> (lambda_q_shift + 1);

    i4_early_cbf_flag += early_cbf;

    /* Right now the depth is hard-coded to 4: The depth can be modified from the config file
    which decides the extent to which TU_REC needs to be done */
    if(i4_cur_depth < i4_max_depth)
    {
        if((cost_child < cost_parent) || (i4_max_tr_size < u1_cur_tr_size))
        {
            //cost_child -= ((4 + 4)  * lambda) >> (lambda_q_shift + 1);
            *pi4_tu_split_cost += ((4 + 4) * lambda) >> (lambda_q_shift + 1);
            tu_split_flag += 1;
            best_cost = cost_child;
        }
        else
        {
            //cost_parent -= ((1 + 1) * lambda) >>  (lambda_q_shift + 1);
            tu_split_flag += 0;
            best_cost = cost_parent;
        }
    }
    else
    {
        //cost_parent -= ((1 + 1) * lambda) >>  (lambda_q_shift + 1);
        tu_split_flag += 0;
        best_cost = cost_parent;
    }

    pi4_16x16_hsad[0] = best_cost;
    pi4_16x16_tu_split[0] = tu_split_flag;
    pi4_16x16_tu_early_cbf[0] = i4_early_cbf_flag;

    /*returning two values(best cost & tu_split_flag) as a single value*/
    return ((best_cost << 10) + (tu_split_flag << 5) + i4_early_cbf_flag);
}

//#endif
/**
*******************************************************************************
*
* @brief
*   Computes 32x32 transform using children 16x16 hadamard results
*
* @par Description:
*
* @param[in] pi2_16x16_had
*  WORD16 pointer to 16x16 hadamard buffer(y0, y1, y2, y3 hadmard in Zscan order)
*
* @param[in] had16_strd
*  stride of 16x16 hadmard buffer pi2_y0, pi2_y1, pi2_y2, pi2_y3
*
* @param[out] pi2_dst
*  destination buffer where 16x16 hadamard result is stored
*
* @param[in] dst_stride
*  stride of destination block
*
* @param[in] i4_frm_qstep
*  frm_qstep value based on the which the threshold value is calculated
*
* @returns
*  32x32 Hadamard SATD
* @remarks
*
*******************************************************************************
*/
//#if COMPUTE_32x32_USING_16X16 == C
UWORD32 ihevce_compute_32x32HAD_using_16x16(
    WORD16 *pi2_16x16_had,
    WORD32 had16_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd,
    WORD32 i4_frm_qstep,
    WORD32 *pi4_cbf)
{
    /* Qstep value is right shifted by 8 */
    WORD32 threshold = (i4_frm_qstep >> 8);

    /* Initialize pointers to 4 subblocks of 8x8 HAD buffer */
    WORD16 *pi2_y0 = pi2_16x16_had;
    WORD16 *pi2_y1 = pi2_16x16_had + 16;
    WORD16 *pi2_y2 = pi2_16x16_had + had16_strd * 16;
    WORD16 *pi2_y3 = pi2_16x16_had + had16_strd * 16 + 16;

    /* Initialize pointers to store 8x8 HAD output */
    WORD16 *pi2_dst0 = pi2_dst;
    WORD16 *pi2_dst1 = pi2_dst + 16;
    WORD16 *pi2_dst2 = pi2_dst + dst_strd * 16;
    WORD16 *pi2_dst3 = pi2_dst + dst_strd * 16 + 16;

    UWORD32 u4_satd = 0;
    WORD32 i;

    /*   Child HAD results combined as follows to get Parent result */
    /*  _                                                 _         */
    /* |  (y0 + y1) + (y2 + y3)    (y0 - y1) + (y2 - y3)   |        */
    /* |  (y0 + y1) - (y2 + y3)    (y0 - y1) - (y2 - y3)   |        */
    /* \-                                                 -/        */
    for(i = 0; i < 256; i++)
    {
        WORD32 src_idx = (i >> 4) * had16_strd + (i % 16);
        WORD32 dst_idx = (i >> 4) * dst_strd + (i % 16);

        WORD16 a0 = pi2_y0[src_idx] >> 2;
        WORD16 a1 = pi2_y1[src_idx] >> 2;
        WORD16 a2 = pi2_y2[src_idx] >> 2;
        WORD16 a3 = pi2_y3[src_idx] >> 2;

        WORD16 b0 = (a0 + a1);
        WORD16 b1 = (a0 - a1);
        WORD16 b2 = (a2 + a3);
        WORD16 b3 = (a2 - a3);

        pi2_dst0[dst_idx] = b0 + b2;
        pi2_dst1[dst_idx] = b1 + b3;
        pi2_dst2[dst_idx] = b0 - b2;
        pi2_dst3[dst_idx] = b1 - b3;

        /* Make the value of dst to zerp, if it falls below the dead-zone */
        if(ABS(pi2_dst0[dst_idx]) > threshold)
            *pi4_cbf = 1;
        if(ABS(pi2_dst1[dst_idx]) > threshold)
            *pi4_cbf = 1;
        if(ABS(pi2_dst2[dst_idx]) > threshold)
            *pi4_cbf = 1;
        if(ABS(pi2_dst3[dst_idx]) > threshold)
            *pi4_cbf = 1;

        u4_satd += ABS(pi2_dst0[dst_idx]);
        u4_satd += ABS(pi2_dst1[dst_idx]);
        u4_satd += ABS(pi2_dst2[dst_idx]);
        u4_satd += ABS(pi2_dst3[dst_idx]);
    }

    /* return 32x32 satd */
    return (u4_satd);
}
//#endif

/**
*******************************************************************************
*
* @brief
*    Hadamard Transform for 32x32 block with 16x6, 8x8 and 4x4 SATD updates.
*    Uses recursive 16x16 had output to compute satd for 32x32 and its children
*
* @par Description:
*
* @param[in] pu1_origin
*  UWORD8 pointer to the current block
*
* @param[in] src_strd
*  WORD32 Source stride
*
* @param[in] pu1_pred
*  UWORD8 pointer to the prediction block
*
* @param[in] pred_strd
*  WORD32 Pred stride
*
* @param[out] pi2_dst
*  WORD16 pointer to the transform output block
*
* @param[out] dst_strd
*  WORD32 Destination stride
*
* @param[out] ppi4_hsad
*   pointer to base pointers for storing hadmard sads of various
*   block sizes (4x4 to 32x32)
*
* @param[in] pos_x_y_4x4
*   Denotes packed x,y postion of current 4x4 block w.r.t to start of ctb/CU/MB
*   Lower 16bits denote xpos and upper 16ypos of the 4x4block
*
* @param[in] num_4x4_in_row
*   Denotes the number of current 4x4 blocks in a ctb/CU/MB
*
* @param[in] lambda
*  lambda values is the cost factor calculated based on QP
*
* @param[in] lambda_q_shift
*  lambda_q_shift used to reverse the lambda value back from q8 format
*
* @param[in] depth
*  depth gives the current TU depth with respect to the CU
*
* @param[in] i4_frm_qstep
*  frm_qstep value based on the which the threshold value is calculated
*
*
* @returns
*
* @remarks
*
*******************************************************************************
*/
void ihevce_had_32x32_r(
    UWORD8 *pu1_src,
    WORD32 src_strd,
    UWORD8 *pu1_pred,
    WORD32 pred_strd,
    WORD16 *pi2_dst,
    WORD32 dst_strd,
    WORD32 **ppi4_hsad,
    WORD32 **ppi4_tu_split,
    WORD32 **ppi4_tu_early_cbf,
    WORD32 pos_x_y_4x4,
    WORD32 num_4x4_in_row,
    WORD32 lambda,
    WORD32 lambda_q_shift,
    WORD32 i4_frm_qstep,
    WORD32 i4_cur_depth,
    WORD32 i4_max_depth,
    WORD32 i4_max_tr_size,
    WORD32 *pi4_tu_split_cost,
    me_func_selector_t *ps_func_selector)

{
    WORD16 ai2_16x16_had[1024];
    WORD32 *pi4_32x32_hsad;
    WORD32 *pi4_32x32_tu_split;
    WORD32 *pi4_32x32_tu_early_cbf;

    WORD32 pos_x = pos_x_y_4x4 & 0xFFFF;
    WORD32 pos_y = (pos_x_y_4x4 >> 16) & 0xFFFF;
    WORD32 tu_split_flag = 0;
    const UWORD8 u1_cur_tr_size = 32;
    WORD32 i4_early_cbf_flag = 0, early_cbf = 0;

    /* cost_parent : Stores the cost of the parent HAD transform (16x16) */
    /* cost_child : Stores the cost of the child HAD transform (16x16) */
    WORD32 cost_child = 0, cost_parent = 0;

    /*retuned as the best cost for the entire TU (32x32) */
    WORD32 best_cost = 0;
    /*captures the best cost and tu_split at child level */
    WORD32 best_cost_tu_split;

    /* Initialize pointers to 4 8x8 blocks in 16x16 */
    WORD16 *pi2_y0 = ai2_16x16_had;
    WORD16 *pi2_y1 = ai2_16x16_had + 16;
    WORD16 *pi2_y2 = ai2_16x16_had + 32 * 16;
    WORD16 *pi2_y3 = ai2_16x16_had + 32 * 16 + 16;

    UWORD8 *pu1_src0 = pu1_src;
    UWORD8 *pu1_src1 = pu1_src + 16;
    UWORD8 *pu1_src2 = pu1_src + src_strd * 16;
    UWORD8 *pu1_src3 = pu1_src + src_strd * 16 + 16;

    UWORD8 *pu1_pred0 = pu1_pred;
    UWORD8 *pu1_pred1 = pu1_pred + 16;
    UWORD8 *pu1_pred2 = pu1_pred + pred_strd * 16;
    UWORD8 *pu1_pred3 = pu1_pred + pred_strd * 16 + 16;

    ASSERT(pos_x >= 0);
    ASSERT(pos_y >= 0);

    /* Initialize pointers to store 32x32 SATDs */
    pi4_32x32_hsad = ppi4_hsad[HAD_32x32] + (pos_x >> 3) + (pos_y >> 3) * (num_4x4_in_row >> 3);

    pi4_32x32_tu_split =
        ppi4_tu_split[HAD_32x32] + (pos_x >> 3) + (pos_y >> 3) * (num_4x4_in_row >> 3);

    pi4_32x32_tu_early_cbf =
        ppi4_tu_early_cbf[HAD_32x32] + (pos_x >> 3) + (pos_y >> 3) * (num_4x4_in_row >> 3);

    /* -------- Compute four 8x8 HAD Transforms of 16x16 call--------- */
    best_cost_tu_split = ps_func_selector->pf_had_16x16_r(
        pu1_src0,
        src_strd,
        pu1_pred0,
        pred_strd,
        pi2_y0,
        32,
        ppi4_hsad,
        ppi4_tu_split,
        ppi4_tu_early_cbf,
        pos_x_y_4x4,
        num_4x4_in_row,
        lambda,
        lambda_q_shift,
        i4_frm_qstep,
        i4_cur_depth + 1,
        i4_max_depth,
        i4_max_tr_size,
        pi4_tu_split_cost,
        NULL);

    /* cost is shifted by 10bits */
    best_cost = best_cost_tu_split >> 10;

    /* Tu split is present in the 6-10 bits */
    tu_split_flag += (best_cost_tu_split & 0x3E0) >> 5;

    /*Early CBF info is present in the last 5 bits */
    i4_early_cbf_flag += best_cost_tu_split & 0x1F;

    tu_split_flag <<= 5;
    i4_early_cbf_flag <<= 5;

    cost_child += best_cost;

    best_cost_tu_split = ps_func_selector->pf_had_16x16_r(
        pu1_src1,
        src_strd,
        pu1_pred1,
        pred_strd,
        pi2_y1,
        32,
        ppi4_hsad,
        ppi4_tu_split,
        ppi4_tu_early_cbf,
        pos_x_y_4x4 + 4,
        num_4x4_in_row,
        lambda,
        lambda_q_shift,
        i4_frm_qstep,
        i4_cur_depth + 1,
        i4_max_depth,
        i4_max_tr_size,
        pi4_tu_split_cost,
        NULL);

    /* cost is shifted by 10bits */
    best_cost = best_cost_tu_split >> 10;

    /* Tu split is present in the 6-10 bits */
    tu_split_flag += (best_cost_tu_split & 0x3E0) >> 5;

    /*Early CBF info is present in the last 5 bits */
    i4_early_cbf_flag += best_cost_tu_split & 0x1F;

    tu_split_flag <<= 5;
    i4_early_cbf_flag <<= 5;

    cost_child += best_cost;

    best_cost_tu_split = ps_func_selector->pf_had_16x16_r(
        pu1_src2,
        src_strd,
        pu1_pred2,
        pred_strd,
        pi2_y2,
        32,
        ppi4_hsad,
        ppi4_tu_split,
        ppi4_tu_early_cbf,
        pos_x_y_4x4 + (4 << 16),
        num_4x4_in_row,
        lambda,
        lambda_q_shift,
        i4_frm_qstep,
        i4_cur_depth + 1,
        i4_max_depth,
        i4_max_tr_size,
        pi4_tu_split_cost,
        NULL);

    /* cost is shifted by 10bits */
    best_cost = best_cost_tu_split >> 10;

    /* Tu split is present in the 6-10 bits */
    tu_split_flag += (best_cost_tu_split & 0x3E0) >> 5;

    /*Early CBF info is present in the last 5 bits */
    i4_early_cbf_flag += best_cost_tu_split & 0x1F;

    tu_split_flag <<= 5;
    i4_early_cbf_flag <<= 5;

    cost_child += best_cost;

    best_cost_tu_split = ps_func_selector->pf_had_16x16_r(
        pu1_src3,
        src_strd,
        pu1_pred3,
        pred_strd,
        pi2_y3,
        32,
        ppi4_hsad,
        ppi4_tu_split,
        ppi4_tu_early_cbf,
        pos_x_y_4x4 + (4 << 16) + 4,
        num_4x4_in_row,
        lambda,
        lambda_q_shift,
        i4_frm_qstep,
        i4_cur_depth + 1,
        i4_max_depth,
        i4_max_tr_size,
        pi4_tu_split_cost,
        NULL);

    /* cost is shifted by 10bits */
    best_cost = best_cost_tu_split >> 10;

    /* Tu split is present in the 6-10 bits */
    tu_split_flag += (best_cost_tu_split & 0x3E0) >> 5;

    /*Early CBF info is present in the last 5 bits */
    i4_early_cbf_flag += best_cost_tu_split & 0x1F;

    tu_split_flag <<= 1;
    i4_early_cbf_flag <<= 1;

    cost_child += best_cost;

    {
        UWORD32 u4_satd = 0;

        u4_satd = ps_func_selector->pf_compute_32x32HAD_using_16x16(
            pi2_y0, 32, pi2_dst, dst_strd, i4_frm_qstep, &early_cbf);

        cost_parent = ((u4_satd + 2) >> 2);
    }

    /* 4 TU_Split flags , 4 CBF Flags*/
    cost_child += ((4 + 4) * lambda) >> (lambda_q_shift + 1);

    i4_early_cbf_flag += early_cbf;

    /* 1 TU_SPlit flag, 1 CBF flag */
    //cost_parent += ((1 + 1)* lambda) >>  (lambda_q_shift + 1);

    if(i4_cur_depth < i4_max_depth)
    {
        if((cost_child < cost_parent) || (u1_cur_tr_size > i4_max_tr_size))
        {
            *pi4_tu_split_cost += ((4 + 4) * lambda) >> (lambda_q_shift + 1);
            best_cost = cost_child;
            tu_split_flag++;
        }
        else
        {
            tu_split_flag = 0;
            best_cost = cost_parent;
        }
    }
    else
    {
        tu_split_flag = 0;
        best_cost = cost_parent;
    }

    pi4_32x32_tu_split[0] = tu_split_flag;

    pi4_32x32_hsad[0] = best_cost;

    pi4_32x32_tu_early_cbf[0] = i4_early_cbf_flag;
}