C++程序  |  2666行  |  93.81 KB

/******************************************************************************
 *
 * 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_tu_tree_selector.c
*
* \brief
*    Functions that facilitate selection of optimal TU tree
*
* \date
*    20/04/2016
*
* \author
*    Ittiam
*
******************************************************************************
*/

/*****************************************************************************/
/* File Includes                                                             */
/*****************************************************************************/
/* System include files */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>
#include <math.h>
#include <limits.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_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_entropy_structs.h"
#include "ihevce_cmn_utils_instr_set_router.h"
#include "ihevce_enc_loop_structs.h"
#include "ihevce_enc_loop_utils.h"
#include "ihevce_tu_tree_selector.h"

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

/*!
******************************************************************************
* \if Function name : ihevce_tu_tree_coverage_in_cu \endif
*
* \brief
*    Determination of the area within the CU that is swept by the TU tree.
*    Input : Pointer to a node of the TU tree
*    Output : Area covered by the current TU or its children
*
*****************************************************************************
*/
WORD32 ihevce_tu_tree_coverage_in_cu(tu_tree_node_t *ps_node)
{
    WORD32 i4_tu_tree_area = 0;

    if(ps_node->u1_is_valid_node)
    {
        i4_tu_tree_area += ps_node->s_luma_data.u1_size * ps_node->s_luma_data.u1_size;
    }
    else
    {
        if(NULL != ps_node->ps_child_node_tl)
        {
            i4_tu_tree_area += ihevce_tu_tree_coverage_in_cu(ps_node->ps_child_node_tl);
        }

        if(NULL != ps_node->ps_child_node_tr)
        {
            i4_tu_tree_area += ihevce_tu_tree_coverage_in_cu(ps_node->ps_child_node_tr);
        }

        if(NULL != ps_node->ps_child_node_bl)
        {
            i4_tu_tree_area += ihevce_tu_tree_coverage_in_cu(ps_node->ps_child_node_bl);
        }

        if(NULL != ps_node->ps_child_node_br)
        {
            i4_tu_tree_area += ihevce_tu_tree_coverage_in_cu(ps_node->ps_child_node_br);
        }
    }

    return i4_tu_tree_area;
}

static void ihevce_tu_node_data_init(
    tu_node_data_t *ps_tu_data, UWORD8 u1_size, UWORD8 u1_posx, UWORD8 u1_posy)
{
    ps_tu_data->u1_size = u1_size;
    ps_tu_data->i8_ssd = 0;
    ps_tu_data->i8_cost = 0;
#if ENABLE_INTER_ZCU_COST
    ps_tu_data->i8_not_coded_cost = 0;
#endif
    ps_tu_data->u4_sad = 0;
    ps_tu_data->i4_bits = 0;
    ps_tu_data->i4_num_bytes_used_for_ecd = 0;
    ps_tu_data->u1_cbf = 0;
    ps_tu_data->u1_reconBufId = UCHAR_MAX;
    ps_tu_data->u1_posx = u1_posx;
    ps_tu_data->u1_posy = u1_posy;
}

/*!
******************************************************************************
* \if Function name : ihevce_tu_node_init \endif
*
* \brief
*    This function initialises all nodes of the TU tree from the root upto and
*    including the nodes at the max tree depth. Only those nodes that lie
*    within the (max + 1) and (min - 1) depths are set as valid. Everything
*    else is invalid. The pointers to the children nodes of the leaf-most
*    nodes in the tree are assigned NULL.
*    Input : Pointer to root of the tree containing TU info.
*    Output : The memory of this node and all its progeny shall be modified
*    returns Number of nodes of the TU tree that have been modified
*
*****************************************************************************
*/
static UWORD16 ihevce_tu_node_init(
    tu_tree_node_t *ps_root,
    UWORD8 u1_size,
    UWORD8 u1_parent_posx,
    UWORD8 u1_parent_posy,
    UWORD8 u1_cur_depth,
    UWORD8 u1_min_tree_depth,
    UWORD8 u1_max_tree_depth,
    UWORD8 u1_chroma_processing_enabled,
    UWORD8 u1_is_422,
    TU_POS_T e_tu_pos)
{
    tu_tree_node_t *ps_node;
    tu_tree_node_t *ps_childNodeTL;
    tu_tree_node_t *ps_childNodeTR;
    tu_tree_node_t *ps_childNodeBL;
    tu_tree_node_t *ps_childNodeBR;

    UWORD8 u1_start_index_for_parent = 0;
    UWORD8 u1_start_index_for_child = 0;
    UWORD16 u2_parent_offset = 0;
    UWORD16 u2_child_offset = 0;
    UWORD8 u1_posx = 0;
    UWORD8 u1_posy = 0;

    const UWORD8 u1_nxn_tu_node_start_index = 0;
    const UWORD8 u1_nBye2xnBye2_tu_node_start_index = 1;
    const UWORD8 u1_nBye4xnBye4_tu_node_start_index = 1 + 4;
    const UWORD8 u1_nBye8xnBye8_tu_node_start_index = 1 + 4 + 16;
    const UWORD8 u1_nBye16xnBye16_tu_node_start_index = 1 + 4 + 16 + 64;
    UWORD16 u2_num_nodes_initialised = 0;

    ASSERT(u1_cur_depth <= u1_max_tree_depth);
    ASSERT(u1_max_tree_depth >= u1_min_tree_depth);

    switch(e_tu_pos)
    {
    case POS_TL:
    {
        u1_posx = u1_parent_posx;
        u1_posy = u1_parent_posy;

        break;
    }
    case POS_TR:
    {
        u1_posx = u1_parent_posx + u1_size;
        u1_posy = u1_parent_posy;

        break;
    }
    case POS_BL:
    {
        u1_posx = u1_parent_posx;
        u1_posy = u1_parent_posy + u1_size;

        break;
    }
    case POS_BR:
    {
        u1_posx = u1_parent_posx + u1_size;
        u1_posy = u1_parent_posy + u1_size;

        break;
    }
    default:
    {
        /* Here be dragons */
        ASSERT(0);
    }
    }

    switch(u1_cur_depth)
    {
    case 0:
    {
        u1_start_index_for_parent = u1_nxn_tu_node_start_index;
        u1_start_index_for_child = u1_nBye2xnBye2_tu_node_start_index;

        u2_parent_offset = 0;
        u2_child_offset = 0;

        break;
    }
    case 1:
    {
        u1_start_index_for_parent = u1_nBye2xnBye2_tu_node_start_index;
        u1_start_index_for_child = u1_nBye4xnBye4_tu_node_start_index;

        u2_parent_offset = e_tu_pos;
        u2_child_offset = 4 * u1_posx / u1_size + 8 * u1_posy / u1_size;

        break;
    }
    case 2:
    {
        u1_start_index_for_parent = u1_nBye4xnBye4_tu_node_start_index;
        u1_start_index_for_child = u1_nBye8xnBye8_tu_node_start_index;

        u2_parent_offset = 2 * u1_parent_posx / u1_size + 4 * u1_parent_posy / u1_size + e_tu_pos;
        u2_child_offset = 4 * u1_posx / u1_size + 16 * u1_posy / u1_size;

        break;
    }
    case 3:
    {
        u1_start_index_for_parent = u1_nBye8xnBye8_tu_node_start_index;
        u1_start_index_for_child = u1_nBye16xnBye16_tu_node_start_index;

        u2_parent_offset = 2 * u1_parent_posx / u1_size + 8 * u1_parent_posy / u1_size + e_tu_pos;
        u2_child_offset = 4 * u1_posx / u1_size + 32 * u1_posy / u1_size;

        break;
    }
    case 4:
    {
        u1_start_index_for_parent = u1_nBye16xnBye16_tu_node_start_index;
        u1_start_index_for_child = 0;

        u2_parent_offset = 2 * u1_parent_posx / u1_size + 16 * u1_parent_posy / u1_size + e_tu_pos;
        u2_child_offset = 0;

        break;
    }
    default:
    {
        /* Here be dragons */
        ASSERT(0);
    }
    }

    ASSERT((u1_start_index_for_parent + u2_parent_offset) < (256 + 64 + 16 + 4 + 1));
    ASSERT((u1_start_index_for_child + u2_child_offset + POS_BR) < (256 + 64 + 16 + 4 + 1));

    ps_node = ps_root + u1_start_index_for_parent + u2_parent_offset;
    ps_childNodeTL = ps_root + u1_start_index_for_child + u2_child_offset + POS_TL;
    ps_childNodeTR = ps_root + u1_start_index_for_child + u2_child_offset + POS_TR;
    ps_childNodeBL = ps_root + u1_start_index_for_child + u2_child_offset + POS_BL;
    ps_childNodeBR = ps_root + u1_start_index_for_child + u2_child_offset + POS_BR;

    ihevce_tu_node_data_init(&ps_node->s_luma_data, u1_size, u1_posx, u1_posy);

    if(u1_chroma_processing_enabled)
    {
        UWORD8 i;

        if(u1_size > 4)
        {
            for(i = 0; i < (u1_is_422 + 1); i++)
            {
                ihevce_tu_node_data_init(
                    &ps_node->as_cb_data[i],
                    u1_size / 2,
                    u1_posx / 2,
                    !u1_is_422 ? u1_posy / 2 : u1_posy + i * u1_size / 2);

                ihevce_tu_node_data_init(
                    &ps_node->as_cr_data[i],
                    u1_size / 2,
                    u1_posx / 2,
                    !u1_is_422 ? u1_posy / 2 : u1_posy + i * u1_size / 2);
            }
        }
        else if(POS_TL == e_tu_pos)
        {
            for(i = 0; i < (u1_is_422 + 1); i++)
            {
                ihevce_tu_node_data_init(
                    &ps_node->as_cb_data[i],
                    u1_size,
                    u1_posx / 2,
                    !u1_is_422 ? u1_posy / 2 : u1_posy + i * u1_size);

                ihevce_tu_node_data_init(
                    &ps_node->as_cr_data[i],
                    u1_size,
                    u1_posx / 2,
                    !u1_is_422 ? u1_posy / 2 : u1_posy + i * u1_size);
            }
        }
        else
        {
            for(i = 0; i < (u1_is_422 + 1); i++)
            {
                ihevce_tu_node_data_init(
                    &ps_node->as_cb_data[i],
                    u1_size / 2,
                    u1_posx / 2,
                    !u1_is_422 ? u1_posy / 2 : u1_posy + i * u1_size);

                ihevce_tu_node_data_init(
                    &ps_node->as_cr_data[i],
                    u1_size / 2,
                    u1_posx / 2,
                    !u1_is_422 ? u1_posy / 2 : u1_posy + i * u1_size);
            }
        }
    }

    if((u1_cur_depth >= u1_min_tree_depth) && (u1_cur_depth <= u1_max_tree_depth))
    {
        ps_node->u1_is_valid_node = 1;
    }
    else
    {
        ps_node->u1_is_valid_node = 0;
    }

    u2_num_nodes_initialised++;

    if((u1_cur_depth < u1_max_tree_depth) && (u1_size > MIN_TU_SIZE))
    {
        ps_node->ps_child_node_tl = ps_childNodeTL;
        ps_node->ps_child_node_tr = ps_childNodeTR;
        ps_node->ps_child_node_bl = ps_childNodeBL;
        ps_node->ps_child_node_br = ps_childNodeBR;

        u2_num_nodes_initialised += ihevce_tu_node_init(
            ps_root,
            u1_size / 2,
            ps_node->s_luma_data.u1_posx,
            ps_node->s_luma_data.u1_posy,
            u1_cur_depth + 1,
            u1_min_tree_depth,
            u1_max_tree_depth,
            u1_chroma_processing_enabled,
            u1_is_422,
            POS_TL);

        u2_num_nodes_initialised += ihevce_tu_node_init(
            ps_root,
            u1_size / 2,
            ps_node->s_luma_data.u1_posx,
            ps_node->s_luma_data.u1_posy,
            u1_cur_depth + 1,
            u1_min_tree_depth,
            u1_max_tree_depth,
            u1_chroma_processing_enabled,
            u1_is_422,
            POS_TR);

        u2_num_nodes_initialised += ihevce_tu_node_init(
            ps_root,
            u1_size / 2,
            ps_node->s_luma_data.u1_posx,
            ps_node->s_luma_data.u1_posy,
            u1_cur_depth + 1,
            u1_min_tree_depth,
            u1_max_tree_depth,
            u1_chroma_processing_enabled,
            u1_is_422,
            POS_BL);

        u2_num_nodes_initialised += ihevce_tu_node_init(
            ps_root,
            u1_size / 2,
            ps_node->s_luma_data.u1_posx,
            ps_node->s_luma_data.u1_posy,
            u1_cur_depth + 1,
            u1_min_tree_depth,
            u1_max_tree_depth,
            u1_chroma_processing_enabled,
            u1_is_422,
            POS_BR);
    }
    else
    {
        ps_node->ps_child_node_tl = NULL;
        ps_node->ps_child_node_tr = NULL;
        ps_node->ps_child_node_bl = NULL;
        ps_node->ps_child_node_br = NULL;
    }

    return u2_num_nodes_initialised;
}

/*!
******************************************************************************
* \if Function name : ihevce_tu_tree_init \endif
*
* \brief
*    Initialises all relevant data within all nodes for a specified TU tree
*    Input : Pointer to root of the tree containing TU info.
*    Output : Returns the number of nodes initialised
*
*****************************************************************************
*/
UWORD16 ihevce_tu_tree_init(
    tu_tree_node_t *ps_root,
    UWORD8 u1_cu_size,
    UWORD8 u1_min_tree_depth,
    UWORD8 u1_max_tree_depth,
    UWORD8 u1_chroma_processing_enabled,
    UWORD8 u1_is_422)
{
    UWORD16 u2_num_nodes = 0;

    ASSERT(u1_max_tree_depth >= u1_min_tree_depth);

    u2_num_nodes += ihevce_tu_node_init(
        ps_root,
        u1_cu_size,
        0,
        0,
        0,
        u1_min_tree_depth,
        u1_max_tree_depth,
        u1_chroma_processing_enabled,
        u1_is_422,
        POS_TL);

    return u2_num_nodes;
}

/*!
******************************************************************************
* \if Function name : ihevce_cabac_bins2Bits_converter_and_state_updater \endif
*
* \brief
*    cabac bin to bits converter
*    Input : 1. Pointer to buffer which stores the current CABAC state. This
*    buffer shall be modified by this function. 2. Index to the cabac state
*    that corresponds to the bin. 3. bin value
*    Output : Number of bits required to encode the bin
*
*****************************************************************************
*/
static INLINE UWORD32 ihevce_cabac_bins2Bits_converter_and_state_updater(
    UWORD8 *pu1_cabac_ctxt, UWORD8 u1_cabac_state_idx, UWORD8 u1_bin_value)
{
    UWORD32 u4_bits = 0;

    u4_bits += gau2_ihevce_cabac_bin_to_bits[pu1_cabac_ctxt[u1_cabac_state_idx] ^ u1_bin_value];
    pu1_cabac_ctxt[u1_cabac_state_idx] =
        gau1_ihevc_next_state[(pu1_cabac_ctxt[u1_cabac_state_idx] << 1) | u1_bin_value];

    return u4_bits;
}

static tu_tree_node_t *
    ihevce_tu_node_parent_finder(tu_tree_node_t *ps_root, tu_tree_node_t *ps_leaf)
{
    UWORD8 u1_depth_of_leaf;

    GETRANGE(u1_depth_of_leaf, ps_root->s_luma_data.u1_size / ps_leaf->s_luma_data.u1_size);
    u1_depth_of_leaf--;

    if(0 == u1_depth_of_leaf)
    {
        return NULL;
    }
    else if(1 == u1_depth_of_leaf)
    {
        return ps_root;
    }
    else
    {
        UWORD8 u1_switch_conditional =
            (ps_leaf->s_luma_data.u1_posx >= ps_root->ps_child_node_tl->s_luma_data.u1_size) +
            (ps_leaf->s_luma_data.u1_posy >= ps_root->ps_child_node_tl->s_luma_data.u1_size) * 2;

        ASSERT(NULL != ps_root->ps_child_node_tl);
        ASSERT(NULL != ps_root->ps_child_node_tr);
        ASSERT(NULL != ps_root->ps_child_node_bl);
        ASSERT(NULL != ps_root->ps_child_node_br);

        switch(u1_switch_conditional)
        {
        case 0:
        {
            return ihevce_tu_node_parent_finder(ps_root->ps_child_node_tl, ps_leaf);
        }
        case 1:
        {
            return ihevce_tu_node_parent_finder(ps_root->ps_child_node_tr, ps_leaf);
        }
        case 2:
        {
            return ihevce_tu_node_parent_finder(ps_root->ps_child_node_bl, ps_leaf);
        }
        case 3:
        {
            return ihevce_tu_node_parent_finder(ps_root->ps_child_node_br, ps_leaf);
        }
        }
    }

    return NULL;
}

/*!
******************************************************************************
* \if Function name : ihevce_compute_bits_for_TUSplit_and_cbf \endif
*
* \notes
*    1. This function ought to be called before the call to 'ihevce_tu_tree_selector'
*    of children TU's in order to determine bits to encode splitFlag as 1.
*    This should also be called at the end of 'ihevce_tu_processor' in order
*    to determine bits required to encode cbf and splitFlag.
*    2. When 'ENABLE_TOP_DOWN_TU_RECURSION' = 0 and 'INCLUDE_CHROMA_DURING_TU_RECURSION' = 1,
*    it shall be assumed that parent chroma cbf is 1.
*    3. When 'INCLUDE_CHROMA_DURING_TU_RECURSION' = 0, this function works as
*    though no chroma related syntax was included in the HEVC syntax for coding
*    the transform tree
*    Input : 1. ps_root: Pointer to root of the tree containing TU info
*            2. ps_leaf: Pointer to current node of the TU tree
*            3. pu1_cabac_ctxt: Pointer to buffer which stores the current CABAC
*            state. This buffer shall be modified by this function
*    Output : Number of bits required to encode cbf and splitFlags
*
*****************************************************************************
*/
static WORD32 ihevce_compute_bits_for_TUSplit_and_cbf(
    tu_tree_node_t *ps_root,
    tu_tree_node_t *ps_leaf,
    UWORD8 *pu1_cabac_ctxt,
    UWORD8 u1_max_tu_size,
    UWORD8 u1_min_tu_size,
    UWORD8 u1_cur_depth,
    UWORD8 u1_max_depth,
    UWORD8 u1_is_intra,
    UWORD8 u1_is_intra_nxn_pu,
    UWORD8 u1_chroma_processing_enabled,
    UWORD8 u1_is_422)
{
    UWORD8 u1_cabac_state_idx;
    UWORD8 u1_log2_tu_size;

    UWORD32 u4_num_bits = 0;
    UWORD8 u1_tu_size = ps_leaf->s_luma_data.u1_size;

    ASSERT(u1_min_tu_size >= MIN_TU_SIZE);
    ASSERT(u1_min_tu_size <= u1_max_tu_size);
    ASSERT(u1_max_tu_size <= MAX_TU_SIZE);
    ASSERT(u1_tu_size >= MIN_TU_SIZE);
    ASSERT(u1_tu_size <= MAX_TU_SIZE);
    ASSERT(u1_cur_depth <= u1_max_depth);

    GETRANGE(u1_log2_tu_size, u1_tu_size);

    if((ps_root->s_luma_data.u1_size >> u1_cur_depth) == u1_tu_size)
    {
        if((u1_tu_size <= u1_max_tu_size) && (u1_tu_size > u1_min_tu_size) &&
           (u1_cur_depth < u1_max_depth) && !(u1_is_intra_nxn_pu && !u1_cur_depth))
        {
            u1_cabac_state_idx = IHEVC_CAB_SPLIT_TFM + (5 - u1_log2_tu_size);
            u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                pu1_cabac_ctxt, u1_cabac_state_idx, 0);
        }

        if(u1_chroma_processing_enabled && (u1_tu_size > 4))
        {
            tu_tree_node_t *ps_parent = ihevce_tu_node_parent_finder(ps_root, ps_leaf);

            u1_cabac_state_idx = IHEVC_CAB_CBCR_IDX + u1_cur_depth;

            if(!u1_cur_depth || ps_parent->as_cb_data[0].u1_cbf || ps_parent->as_cb_data[1].u1_cbf)
            {
                if(u1_is_422)
                {
                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cb_data[0].u1_cbf);

                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cb_data[1].u1_cbf);
                }
                else
                {
                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cb_data[0].u1_cbf);
                }
            }

            if(!u1_cur_depth || ps_parent->as_cr_data[0].u1_cbf || ps_parent->as_cr_data[1].u1_cbf)
            {
                if(u1_is_422)
                {
                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cr_data[0].u1_cbf);

                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cr_data[1].u1_cbf);
                }
                else
                {
                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cr_data[0].u1_cbf);
                }
            }
        }

        if(u1_is_intra || u1_cur_depth)
        {
            u1_cabac_state_idx = IHEVC_CAB_CBF_LUMA_IDX + !u1_cur_depth;
            u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->s_luma_data.u1_cbf);
        }
    }
    else
    {
        if((u1_tu_size <= u1_max_tu_size) && (u1_tu_size > u1_min_tu_size) &&
           (u1_cur_depth < u1_max_depth) && !(u1_is_intra_nxn_pu && !u1_cur_depth))
        {
            u1_cabac_state_idx = IHEVC_CAB_SPLIT_TFM + (5 - u1_log2_tu_size);
            u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                pu1_cabac_ctxt, u1_cabac_state_idx, 1);
        }

        if(u1_chroma_processing_enabled && (u1_tu_size > 4))
        {
            tu_tree_node_t *ps_parent = ihevce_tu_node_parent_finder(ps_root, ps_leaf);

            u1_cabac_state_idx = IHEVC_CAB_CBCR_IDX + u1_cur_depth;

            if(!u1_cur_depth || ps_parent->as_cb_data[0].u1_cbf || ps_parent->as_cb_data[1].u1_cbf)
            {
                if(u1_is_422 && (8 == u1_tu_size))
                {
                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cb_data[0].u1_cbf);

                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cb_data[1].u1_cbf);
                }
                else
                {
                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt,
                        u1_cabac_state_idx,
                        ps_leaf->as_cb_data[0].u1_cbf || ps_leaf->as_cb_data[1].u1_cbf);
                }
            }

            if(!u1_cur_depth || ps_parent->as_cr_data[0].u1_cbf || ps_parent->as_cr_data[1].u1_cbf)
            {
                if(u1_is_422 && (8 == u1_tu_size))
                {
                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cr_data[0].u1_cbf);

                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt, u1_cabac_state_idx, ps_leaf->as_cr_data[1].u1_cbf);
                }
                else
                {
                    u4_num_bits += ihevce_cabac_bins2Bits_converter_and_state_updater(
                        pu1_cabac_ctxt,
                        u1_cabac_state_idx,
                        ps_leaf->as_cr_data[0].u1_cbf || ps_leaf->as_cr_data[1].u1_cbf);
                }
            }
        }
    }

    return u4_num_bits;
}

/*!
******************************************************************************
* \if Function name : ihevce_tu_processor \endif
*
* \notes
*    Input : 1. ps_ctxt: Pointer to enc-loop's context. Parts of this structure
*            shall be modified by this function. They include, au1_cu_csbf,
*            i8_cu_not_coded_cost, ai2_scratch and s_rdoq_sbh_ctxt
*            2. ps_node: Pointer to current node of the TU tree. This struct
*            shall be modified by this function
*            3. pv_src: Pointer to buffer which stores the source
*            4. pv_pred: Pointer to buffer which stores the pred
*            5. pv_recon: Pointer to buffer which stores the recon
*            This buffer shall be modified by this function
*            6. pi2_deq_data: Pointer to buffer which stores the output of IQ.
*            This buffer shall be modified by this function
*            7. pu1_ecd: Pointer to buffer which stores the data output by
*            entropy coding. This buffer shall be modified by this function
*            8. pu1_cabac_ctxt: Pointer to buffer which stores the current CABAC
*            state. This buffer shall be modified by this function
*    Output : NA
*
*****************************************************************************
*/
static void ihevce_tu_processor(
    ihevce_enc_loop_ctxt_t *ps_ctxt,
    tu_tree_node_t *ps_node,
    buffer_data_for_tu_t *ps_buffer_data,
    UWORD8 *pu1_cabac_ctxt,
    WORD32 i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
    WORD32 i4_alpha_stim_multiplier,
    UWORD8 u1_is_cu_noisy,
#endif
    UWORD8 u1_chroma_processing_enabled,
    UWORD8 u1_compute_spatial_ssd)
{
    UWORD8 u1_is_recon_available;

    void *pv_src = ps_buffer_data->s_src_pred_rec_buf_luma.pv_src;
    void *pv_pred = ps_buffer_data->s_src_pred_rec_buf_luma.pv_pred;
    void *pv_recon = ps_buffer_data->s_src_pred_rec_buf_luma.pv_recon;
    WORD16 *pi2_deq_data = ps_buffer_data->pi2_deq_data;
    UWORD8 *pu1_ecd = ps_buffer_data->ppu1_ecd[0];
    WORD32 i4_src_stride = ps_buffer_data->s_src_pred_rec_buf_luma.i4_src_stride;
    WORD32 i4_pred_stride = ps_buffer_data->s_src_pred_rec_buf_luma.i4_pred_stride;
    WORD32 i4_recon_stride = ps_buffer_data->s_src_pred_rec_buf_luma.i4_recon_stride;
    WORD32 i4_deq_data_stride = ps_buffer_data->i4_deq_data_stride;
    UWORD8 u1_size = ps_node->s_luma_data.u1_size;
    UWORD8 u1_posx = ps_node->s_luma_data.u1_posx;
    UWORD8 u1_posy = ps_node->s_luma_data.u1_posy;
    WORD32 trans_size = (64 == u1_size) ? 32 : u1_size;
    UWORD8 u1_is_422 = (ps_ctxt->u1_chroma_array_type == 2);

    (void)pu1_cabac_ctxt;
    {
        pv_src = ((UWORD8 *)pv_src) + u1_posx + u1_posy * i4_src_stride;
        pv_pred = ((UWORD8 *)pv_pred) + u1_posx + u1_posy * i4_pred_stride;
        pv_recon = ((UWORD8 *)pv_recon) + u1_posx + u1_posy * i4_recon_stride;
    }

    pi2_deq_data += u1_posx + u1_posy * i4_deq_data_stride;

    /*2 Multi- dimensinal array based on trans size  of rounding factor to be added here */
    /* arrays are for rounding factor corr. to 0-1 decision and 1-2 decision */
    /* Currently the complete array will contain only single value*/
    /*The rounding factor is calculated with the formula
    Deadzone val = (((R1 - R0) * (2^(-8/3)) * lamMod) + 1)/2
    rounding factor = (1 - DeadZone Val)

    Assumption: Cabac states of All the sub-blocks in the TU are considered independent
    */
    if((ps_ctxt->i4_quant_rounding_level == TU_LEVEL_QUANT_ROUNDING) &&
       (ps_node->s_luma_data.u1_posx || ps_node->s_luma_data.u1_posy))
    {
        double i4_lamda_modifier;

        if((BSLICE == ps_ctxt->i1_slice_type) && (ps_ctxt->i4_temporal_layer_id))
        {
            i4_lamda_modifier = ps_ctxt->i4_lamda_modifier *
                                CLIP3((((double)(ps_ctxt->i4_cu_qp - 12)) / 6.0), 2.00, 4.00);
        }
        else
        {
            i4_lamda_modifier = ps_ctxt->i4_lamda_modifier;
        }
        if(ps_ctxt->i4_use_const_lamda_modifier)
        {
            if(ISLICE == ps_ctxt->i1_slice_type)
            {
                i4_lamda_modifier = ps_ctxt->f_i_pic_lamda_modifier;
            }
            else
            {
                i4_lamda_modifier = CONST_LAMDA_MOD_VAL;
            }
        }
        ps_ctxt->pi4_quant_round_factor_tu_0_1[trans_size >> 3] = &ps_ctxt->i4_quant_round_tu[0][0];
        ps_ctxt->pi4_quant_round_factor_tu_1_2[trans_size >> 3] = &ps_ctxt->i4_quant_round_tu[1][0];

        memset(
            ps_ctxt->pi4_quant_round_factor_tu_0_1[trans_size >> 3],
            0,
            trans_size * trans_size * sizeof(WORD32));
        memset(
            ps_ctxt->pi4_quant_round_factor_tu_1_2[trans_size >> 3],
            0,
            trans_size * trans_size * sizeof(WORD32));

        ihevce_quant_rounding_factor_gen(
            trans_size,
            1,
            &ps_ctxt->s_rdopt_entropy_ctxt,
            ps_ctxt->pi4_quant_round_factor_tu_0_1[trans_size >> 3],
            ps_ctxt->pi4_quant_round_factor_tu_1_2[trans_size >> 3],
            i4_lamda_modifier,
            1);
    }
    else
    {
        ps_ctxt->pi4_quant_round_factor_tu_0_1[trans_size >> 3] =
            ps_ctxt->pi4_quant_round_factor_cu_ctb_0_1[trans_size >> 3];
        ps_ctxt->pi4_quant_round_factor_tu_1_2[trans_size >> 3] =
            ps_ctxt->pi4_quant_round_factor_cu_ctb_1_2[trans_size >> 3];
    }

#if ENABLE_INTER_ZCU_COST
    ps_ctxt->i8_cu_not_coded_cost = 0;
#endif

    {
        ps_node->s_luma_data.u1_cbf = ihevce_t_q_iq_ssd_scan_fxn(
            ps_ctxt,
            (UWORD8 *)pv_pred,
            i4_pred_stride,
            (UWORD8 *)pv_src,
            i4_src_stride,
            pi2_deq_data,
            i4_deq_data_stride,
            (UWORD8 *)pv_recon,
            i4_recon_stride,
            pu1_ecd,
            ps_ctxt->au1_cu_csbf,
            ps_ctxt->i4_cu_csbf_strd,
            u1_size,
            i4_pred_mode,
            &ps_node->s_luma_data.i8_ssd,
            &ps_node->s_luma_data.i4_num_bytes_used_for_ecd,
            &ps_node->s_luma_data.i4_bits,
            &ps_node->s_luma_data.u4_sad,
            &ps_node->s_luma_data.i4_zero_col,
            &ps_node->s_luma_data.i4_zero_row,
            &u1_is_recon_available,
            ps_ctxt->s_rdoq_sbh_ctxt.i4_perform_all_cand_rdoq,
            ps_ctxt->s_rdoq_sbh_ctxt.i4_perform_all_cand_sbh,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
            i4_alpha_stim_multiplier,
            u1_is_cu_noisy,
#endif
            u1_compute_spatial_ssd ? SPATIAL_DOMAIN_SSD : FREQUENCY_DOMAIN_SSD,
            1);
    }

#if ENABLE_INTER_ZCU_COST
    ps_node->s_luma_data.i8_not_coded_cost = ps_ctxt->i8_cu_not_coded_cost;
#endif

    if(u1_compute_spatial_ssd && u1_is_recon_available)
    {
        ps_node->s_luma_data.u1_reconBufId = 0;
    }
    else
    {
        ps_node->s_luma_data.u1_reconBufId = UCHAR_MAX;
    }

    ps_node->s_luma_data.i8_cost =
        ps_node->s_luma_data.i8_ssd +
        COMPUTE_RATE_COST_CLIP30(
            ps_node->s_luma_data.i4_bits, ps_ctxt->i8_cl_ssd_lambda_qf, LAMBDA_Q_SHIFT);

    pu1_ecd += ps_node->s_luma_data.i4_num_bytes_used_for_ecd;

    if(u1_chroma_processing_enabled &&
       ((!(u1_posx % 8) && !(u1_posy % 8) && (4 == u1_size)) || (u1_size > 4)))
    {
        UWORD8 i;
        void *pv_chroma_src;
        void *pv_chroma_pred;
        void *pv_chroma_recon;
        WORD16 *pi2_deq_data_chroma;

        WORD32 i4_chroma_src_stride = ps_buffer_data->s_src_pred_rec_buf_chroma.i4_src_stride;
        WORD32 i4_chroma_pred_stride = ps_buffer_data->s_src_pred_rec_buf_chroma.i4_pred_stride;
        WORD32 i4_chroma_recon_stride = ps_buffer_data->s_src_pred_rec_buf_chroma.i4_recon_stride;
        WORD32 i4_deq_data_stride_chroma = ps_buffer_data->i4_deq_data_stride_chroma;

        /* SubTU loop */
        for(i = 0; i < u1_is_422 + 1; i++)
        {
            UWORD8 u1_chroma_size = ps_node->as_cb_data[i].u1_size;
            UWORD8 u1_chroma_posx = ps_node->as_cb_data[i].u1_posx;
            UWORD8 u1_chroma_posy = ps_node->as_cb_data[i].u1_posy;

#if ENABLE_INTER_ZCU_COST
            ps_ctxt->i8_cu_not_coded_cost = 0;
#endif

            pi2_deq_data_chroma = ps_buffer_data->pi2_deq_data_chroma + (u1_chroma_posx * 2) +
                                  u1_chroma_posy * i4_deq_data_stride_chroma;

            {
                pv_chroma_src = ((UWORD8 *)ps_buffer_data->s_src_pred_rec_buf_chroma.pv_src) +
                                (u1_chroma_posx * 2) + u1_chroma_posy * i4_chroma_src_stride;
                pv_chroma_pred = ((UWORD8 *)ps_buffer_data->s_src_pred_rec_buf_chroma.pv_pred) +
                                 (u1_chroma_posx * 2) + u1_chroma_posy * i4_chroma_pred_stride;
                pv_chroma_recon = ((UWORD8 *)ps_buffer_data->s_src_pred_rec_buf_chroma.pv_recon) +
                                  (u1_chroma_posx * 2) + u1_chroma_posy * i4_chroma_recon_stride;

                ps_node->as_cb_data[i].u1_cbf = ihevce_chroma_t_q_iq_ssd_scan_fxn(
                    ps_ctxt,
                    (UWORD8 *)pv_chroma_pred,
                    i4_chroma_pred_stride,
                    (UWORD8 *)pv_chroma_src,
                    i4_chroma_src_stride,
                    pi2_deq_data_chroma,
                    i4_deq_data_stride_chroma,
                    (UWORD8 *)pv_chroma_recon,
                    i4_chroma_recon_stride,
                    pu1_ecd,
                    ps_ctxt->au1_cu_csbf,
                    ps_ctxt->i4_cu_csbf_strd,
                    u1_chroma_size,
                    SCAN_DIAG_UPRIGHT,
                    0,
                    &ps_node->as_cb_data[i].i4_num_bytes_used_for_ecd,
                    &ps_node->as_cb_data[i].i4_bits,
                    &ps_node->as_cb_data[i].i4_zero_col,
                    &ps_node->as_cb_data[i].i4_zero_row,
                    &u1_is_recon_available,
                    ps_ctxt->s_rdoq_sbh_ctxt.i4_perform_all_cand_rdoq,
                    ps_ctxt->s_rdoq_sbh_ctxt.i4_perform_all_cand_sbh,
                    &ps_node->as_cb_data[i].i8_ssd,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
                    i4_alpha_stim_multiplier,
                    u1_is_cu_noisy,
#endif
                    i4_pred_mode == PRED_MODE_SKIP,
                    u1_compute_spatial_ssd ? SPATIAL_DOMAIN_SSD : FREQUENCY_DOMAIN_SSD,
                    U_PLANE);
            }

#if ENABLE_INTER_ZCU_COST
            ps_node->as_cb_data[i].i8_not_coded_cost = ps_ctxt->i8_cu_not_coded_cost;
#endif

            if(u1_compute_spatial_ssd && u1_is_recon_available)
            {
                ps_node->as_cb_data[i].u1_reconBufId = 0;
            }
            else
            {
                ps_node->as_cb_data[i].u1_reconBufId = UCHAR_MAX;
            }

            ps_node->as_cb_data[i].i8_cost =
                ps_node->as_cb_data[i].i8_ssd + COMPUTE_RATE_COST_CLIP30(
                                                    ps_node->as_cb_data[i].i4_bits,
                                                    ps_ctxt->i8_cl_ssd_lambda_chroma_qf,
                                                    LAMBDA_Q_SHIFT);

#if WEIGH_CHROMA_COST
            ps_node->as_cb_data[i].i8_cost =
                (ps_node->as_cb_data[i].i8_cost * ps_ctxt->u4_chroma_cost_weighing_factor +
                 (1 << (CHROMA_COST_WEIGHING_FACTOR_Q_SHIFT - 1))) >>
                CHROMA_COST_WEIGHING_FACTOR_Q_SHIFT;
#endif

            pu1_ecd += ps_node->as_cb_data[i].i4_num_bytes_used_for_ecd;
        }

        for(i = 0; i < u1_is_422 + 1; i++)
        {
            UWORD8 u1_chroma_size = ps_node->as_cr_data[i].u1_size;
            UWORD8 u1_chroma_posx = ps_node->as_cr_data[i].u1_posx;
            UWORD8 u1_chroma_posy = ps_node->as_cr_data[i].u1_posy;

#if ENABLE_INTER_ZCU_COST
            ps_ctxt->i8_cu_not_coded_cost = 0;
#endif

            pi2_deq_data_chroma = ps_buffer_data->pi2_deq_data_chroma + u1_chroma_size +
                                  (u1_chroma_posx * 2) + u1_chroma_posy * i4_deq_data_stride_chroma;

            {
                pv_chroma_src = ((UWORD8 *)ps_buffer_data->s_src_pred_rec_buf_chroma.pv_src) +
                                (u1_chroma_posx * 2) + u1_chroma_posy * i4_chroma_src_stride;
                pv_chroma_pred = ((UWORD8 *)ps_buffer_data->s_src_pred_rec_buf_chroma.pv_pred) +
                                 (u1_chroma_posx * 2) + u1_chroma_posy * i4_chroma_pred_stride;
                pv_chroma_recon = ((UWORD8 *)ps_buffer_data->s_src_pred_rec_buf_chroma.pv_recon) +
                                  (u1_chroma_posx * 2) + u1_chroma_posy * i4_chroma_recon_stride;

                ps_node->as_cr_data[i].u1_cbf = ihevce_chroma_t_q_iq_ssd_scan_fxn(
                    ps_ctxt,
                    (UWORD8 *)pv_chroma_pred,
                    i4_chroma_pred_stride,
                    (UWORD8 *)pv_chroma_src,
                    i4_chroma_src_stride,
                    pi2_deq_data_chroma,
                    i4_deq_data_stride_chroma,
                    (UWORD8 *)pv_chroma_recon,
                    i4_chroma_recon_stride,
                    pu1_ecd,
                    ps_ctxt->au1_cu_csbf,
                    ps_ctxt->i4_cu_csbf_strd,
                    u1_chroma_size,
                    SCAN_DIAG_UPRIGHT,
                    0,
                    &ps_node->as_cr_data[i].i4_num_bytes_used_for_ecd,
                    &ps_node->as_cr_data[i].i4_bits,
                    &ps_node->as_cr_data[i].i4_zero_col,
                    &ps_node->as_cr_data[i].i4_zero_row,
                    &u1_is_recon_available,
                    ps_ctxt->s_rdoq_sbh_ctxt.i4_perform_all_cand_rdoq,
                    ps_ctxt->s_rdoq_sbh_ctxt.i4_perform_all_cand_sbh,
                    &ps_node->as_cr_data[i].i8_ssd,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
                    i4_alpha_stim_multiplier,
                    u1_is_cu_noisy,
#endif
                    i4_pred_mode == PRED_MODE_SKIP,
                    u1_compute_spatial_ssd ? SPATIAL_DOMAIN_SSD : FREQUENCY_DOMAIN_SSD,
                    V_PLANE);
            }

#if ENABLE_INTER_ZCU_COST
            ps_node->as_cr_data[i].i8_not_coded_cost = ps_ctxt->i8_cu_not_coded_cost;
#endif

            if(u1_compute_spatial_ssd && u1_is_recon_available)
            {
                ps_node->as_cr_data[i].u1_reconBufId = 0;
            }
            else
            {
                ps_node->as_cr_data[i].u1_reconBufId = UCHAR_MAX;
            }

            ps_node->as_cr_data[i].i8_cost =
                ps_node->as_cr_data[i].i8_ssd + COMPUTE_RATE_COST_CLIP30(
                                                    ps_node->as_cr_data[i].i4_bits,
                                                    ps_ctxt->i8_cl_ssd_lambda_chroma_qf,
                                                    LAMBDA_Q_SHIFT);

#if WEIGH_CHROMA_COST
            ps_node->as_cr_data[i].i8_cost =
                (ps_node->as_cr_data[i].i8_cost * ps_ctxt->u4_chroma_cost_weighing_factor +
                 (1 << (CHROMA_COST_WEIGHING_FACTOR_Q_SHIFT - 1))) >>
                CHROMA_COST_WEIGHING_FACTOR_Q_SHIFT;
#endif

            pu1_ecd += ps_node->as_cr_data[i].i4_num_bytes_used_for_ecd;
        }
    }
}

static INLINE void ihevce_nbr_data_copier(
    nbr_4x4_t *ps_nbr_data_buf,
    WORD32 i4_nbr_data_buf_stride,
    WORD32 i4_cu_qp,
    UWORD8 u1_cbf,
    WORD32 u1_posx,
    UWORD8 u1_posy,
    UWORD8 u1_size)
{
    WORD32 i, j;

    UWORD8 u1_num_4x4_in_tu = u1_size / 4;

    ps_nbr_data_buf += ((u1_posx) / 4) + (u1_posy / 4) * i4_nbr_data_buf_stride;

    for(i = 0; i < u1_num_4x4_in_tu; i++)
    {
        for(j = 0; j < u1_num_4x4_in_tu; j++)
        {
            ps_nbr_data_buf[j].b8_qp = i4_cu_qp;
            ps_nbr_data_buf[j].b1_y_cbf = u1_cbf;
        }

        ps_nbr_data_buf += i4_nbr_data_buf_stride;
    }
}

static INLINE void ihevce_debriefer_when_parent_wins(
    tu_tree_node_t *ps_node,
    FT_COPY_2D *pf_copy_2d,
    FT_CHROMA_INTERLEAVE_2D_COPY *pf_chroma_interleave_2d_copy,
    nbr_4x4_t *ps_nbr_data_buf,
    WORD16 *pi2_deq_data_src,
    WORD16 *pi2_deq_data_dst,
    WORD16 *pi2_deq_data_src_chroma,
    WORD16 *pi2_deq_data_dst_chroma,
    void *pv_recon_src,
    void *pv_recon_dst,
    void *pv_recon_src_chroma,
    void *pv_recon_dst_chroma,
    UWORD8 *pu1_cabac_ctxt_src,
    UWORD8 *pu1_cabac_ctxt_dst,
    UWORD8 *pu1_ecd_src,
    UWORD8 *pu1_ecd_dst,
    WORD32 i4_nbr_data_buf_stride,
    WORD32 i4_deq_data_src_stride,
    WORD32 i4_deq_data_dst_stride,
    WORD32 i4_deq_data_src_stride_chroma,
    WORD32 i4_deq_data_dst_stride_chroma,
    WORD32 i4_recon_src_stride,
    WORD32 i4_recon_dst_stride,
    WORD32 i4_recon_src_stride_chroma,
    WORD32 i4_recon_dst_stride_chroma,
    WORD32 i4_cabac_state_table_size,
    WORD32 i4_cu_qp,
    UWORD8 u1_chroma_processing_enabled,
    UWORD8 u1_is_422,
    UWORD8 u1_is_hbd)
{
    UWORD8 i;

    UWORD32 u4_num_ecd_bytes = 0;

    /* Y */
    {
        UWORD8 u1_posx = ps_node->s_luma_data.u1_posx;
        UWORD8 u1_posy = ps_node->s_luma_data.u1_posy;
        UWORD8 *pu1_deq_data_dst =
            (UWORD8 *)(pi2_deq_data_dst + u1_posx + u1_posy * i4_deq_data_dst_stride);
        UWORD8 *pu1_deq_data_src =
            (UWORD8 *)(pi2_deq_data_src + u1_posx + u1_posy * i4_deq_data_src_stride);
        UWORD8 *pu1_recon_dst;
        UWORD8 *pu1_recon_src;

        {
            pu1_recon_dst = (((UWORD8 *)pv_recon_dst) + u1_posx + u1_posy * i4_recon_dst_stride);
            pu1_recon_src = (((UWORD8 *)pv_recon_src) + u1_posx + u1_posy * i4_recon_src_stride);
        }
        u4_num_ecd_bytes += ps_node->s_luma_data.i4_num_bytes_used_for_ecd;

        if(ps_node->s_luma_data.u1_reconBufId != UCHAR_MAX)
        {
            pf_copy_2d(
                pu1_recon_dst,
                i4_recon_dst_stride * (u1_is_hbd + 1),
                pu1_recon_src,
                i4_recon_src_stride * (u1_is_hbd + 1),
                ps_node->s_luma_data.u1_size * (u1_is_hbd + 1),
                ps_node->s_luma_data.u1_size);
        }
        else if(ps_node->s_luma_data.u1_cbf)
        {
            pf_copy_2d(
                pu1_deq_data_dst,
                i4_deq_data_dst_stride * 2,
                pu1_deq_data_src,
                i4_deq_data_src_stride * 2,
                ps_node->s_luma_data.u1_size * 2,
                ps_node->s_luma_data.u1_size);
        }
    }

    /* Cb */
    if(u1_chroma_processing_enabled)
    {
        for(i = 0; i < u1_is_422 + 1; i++)
        {
            UWORD8 u1_posx = ps_node->as_cb_data[i].u1_posx;
            UWORD8 u1_posy = ps_node->as_cb_data[i].u1_posy;
            UWORD8 *pu1_deq_data_dst =
                (UWORD8
                     *)(pi2_deq_data_dst_chroma + (u1_posx * 2) + (u1_posy * i4_deq_data_dst_stride_chroma));
            UWORD8 *pu1_deq_data_src =
                (UWORD8
                     *)(pi2_deq_data_src_chroma + (u1_posx * 2) + (u1_posy * i4_deq_data_src_stride_chroma));
            UWORD8 *pu1_recon_dst;
            UWORD8 *pu1_recon_src;

            {
                pu1_recon_dst =
                    (((UWORD8 *)pv_recon_dst_chroma) + (u1_posx * 2) +
                     u1_posy * i4_recon_dst_stride_chroma);
                pu1_recon_src =
                    (((UWORD8 *)pv_recon_src_chroma) + (u1_posx * 2) +
                     u1_posy * i4_recon_src_stride_chroma);
            }
            u4_num_ecd_bytes += ps_node->as_cb_data[i].i4_num_bytes_used_for_ecd;

            if(ps_node->as_cb_data[i].u1_reconBufId != UCHAR_MAX)
            {
                {
                    pf_chroma_interleave_2d_copy(
                        pu1_recon_src,
                        i4_recon_src_stride_chroma * (u1_is_hbd + 1),
                        pu1_recon_dst,
                        i4_recon_dst_stride_chroma * (u1_is_hbd + 1),
                        ps_node->as_cb_data[i].u1_size * (u1_is_hbd + 1),
                        ps_node->as_cb_data[i].u1_size,
                        U_PLANE);
                }
            }
            else if(ps_node->as_cb_data[i].u1_cbf)
            {
                pf_copy_2d(
                    pu1_deq_data_dst,
                    i4_deq_data_dst_stride_chroma * 2,
                    pu1_deq_data_src,
                    i4_deq_data_src_stride_chroma * 2,
                    ps_node->as_cb_data[i].u1_size * 2,
                    ps_node->as_cb_data[i].u1_size);
            }
        }

        /* Cr */
        for(i = 0; i < u1_is_422 + 1; i++)
        {
            UWORD8 u1_posx = ps_node->as_cr_data[i].u1_posx;
            UWORD8 u1_posy = ps_node->as_cr_data[i].u1_posy;
            UWORD8 *pu1_deq_data_dst =
                (UWORD8
                     *)(pi2_deq_data_dst_chroma + ps_node->as_cr_data[i].u1_size + (u1_posx * 2) + (u1_posy * i4_deq_data_dst_stride_chroma));
            UWORD8 *pu1_deq_data_src =
                (UWORD8
                     *)(pi2_deq_data_src_chroma + ps_node->as_cr_data[i].u1_size + (u1_posx * 2) + (u1_posy * i4_deq_data_src_stride_chroma));
            UWORD8 *pu1_recon_dst;
            UWORD8 *pu1_recon_src;

            {
                pu1_recon_dst =
                    (((UWORD8 *)pv_recon_dst_chroma) + (u1_posx * 2) +
                     u1_posy * i4_recon_dst_stride_chroma);
                pu1_recon_src =
                    (((UWORD8 *)pv_recon_src_chroma) + (u1_posx * 2) +
                     u1_posy * i4_recon_src_stride_chroma);
            }
            u4_num_ecd_bytes += ps_node->as_cr_data[i].i4_num_bytes_used_for_ecd;

            if(ps_node->as_cr_data[i].u1_reconBufId != UCHAR_MAX)
            {
                {
                    pf_chroma_interleave_2d_copy(
                        pu1_recon_src,
                        i4_recon_src_stride_chroma * (u1_is_hbd + 1),
                        pu1_recon_dst,
                        i4_recon_dst_stride_chroma * (u1_is_hbd + 1),
                        ps_node->as_cr_data[i].u1_size * (u1_is_hbd + 1),
                        ps_node->as_cr_data[i].u1_size,
                        V_PLANE);
                }
            }
            else if(ps_node->as_cr_data[i].u1_cbf)
            {
                pf_copy_2d(
                    pu1_deq_data_dst,
                    i4_deq_data_dst_stride_chroma * 2,
                    pu1_deq_data_src,
                    i4_deq_data_src_stride_chroma * 2,
                    ps_node->as_cr_data[i].u1_size * 2,
                    ps_node->as_cr_data[i].u1_size);
            }
        }
    }

    if(pu1_ecd_dst != pu1_ecd_src)
    {
        memmove(pu1_ecd_dst, pu1_ecd_src, u4_num_ecd_bytes);
    }

    memcpy(pu1_cabac_ctxt_dst, pu1_cabac_ctxt_src, i4_cabac_state_table_size);

    ihevce_nbr_data_copier(
        ps_nbr_data_buf,
        i4_nbr_data_buf_stride,
        i4_cu_qp,
        ps_node->s_luma_data.u1_cbf,
        ps_node->s_luma_data.u1_posx,
        ps_node->s_luma_data.u1_posy,
        ps_node->s_luma_data.u1_size);

    ps_node->ps_child_node_tl = NULL;
    ps_node->ps_child_node_tr = NULL;
    ps_node->ps_child_node_bl = NULL;
    ps_node->ps_child_node_br = NULL;
}

/*!
******************************************************************************
* \if Function name : ihevce_ecd_buffer_pointer_updater \endif
*
* \brief
*    Updates ppu1_ecd with current pointer
*    Output : Number of byte positions 'pu1_ecd_buf_ptr_at_t0' is incremented by
*
*****************************************************************************
*/
static INLINE UWORD32 ihevce_ecd_buffer_pointer_updater(
    tu_tree_node_t *ps_node,
    UWORD8 **ppu1_ecd,
    UWORD8 *pu1_ecd_buf_ptr_at_t0,
    UWORD8 u1_parent_has_won,
    UWORD8 u1_chroma_processing_enabled,
    UWORD8 u1_is_422)
{
    UWORD8 i;

    UWORD32 u4_num_bytes = 0;

    if(u1_parent_has_won)
    {
        u4_num_bytes += ps_node->s_luma_data.i4_num_bytes_used_for_ecd;

        if(u1_chroma_processing_enabled)
        {
            for(i = 0; i < u1_is_422 + 1; i++)
            {
                u4_num_bytes += ps_node->as_cb_data[i].i4_num_bytes_used_for_ecd;
                u4_num_bytes += ps_node->as_cr_data[i].i4_num_bytes_used_for_ecd;
            }
        }
    }
    else
    {
        u4_num_bytes += ps_node->ps_child_node_tl->s_luma_data.i4_num_bytes_used_for_ecd;
        u4_num_bytes += ps_node->ps_child_node_tr->s_luma_data.i4_num_bytes_used_for_ecd;
        u4_num_bytes += ps_node->ps_child_node_bl->s_luma_data.i4_num_bytes_used_for_ecd;
        u4_num_bytes += ps_node->ps_child_node_br->s_luma_data.i4_num_bytes_used_for_ecd;

        if(u1_chroma_processing_enabled)
        {
            for(i = 0; i < u1_is_422 + 1; i++)
            {
                u4_num_bytes += ps_node->ps_child_node_tl->as_cb_data[i].i4_num_bytes_used_for_ecd;
                u4_num_bytes += ps_node->ps_child_node_tl->as_cr_data[i].i4_num_bytes_used_for_ecd;
                u4_num_bytes += ps_node->ps_child_node_tr->as_cb_data[i].i4_num_bytes_used_for_ecd;
                u4_num_bytes += ps_node->ps_child_node_tr->as_cr_data[i].i4_num_bytes_used_for_ecd;
                u4_num_bytes += ps_node->ps_child_node_bl->as_cb_data[i].i4_num_bytes_used_for_ecd;
                u4_num_bytes += ps_node->ps_child_node_bl->as_cr_data[i].i4_num_bytes_used_for_ecd;
                u4_num_bytes += ps_node->ps_child_node_br->as_cb_data[i].i4_num_bytes_used_for_ecd;
                u4_num_bytes += ps_node->ps_child_node_br->as_cr_data[i].i4_num_bytes_used_for_ecd;
            }
        }
    }

    ppu1_ecd[0] = pu1_ecd_buf_ptr_at_t0 + u4_num_bytes;

    return u4_num_bytes;
}

static INLINE LWORD64 ihevce_tu_node_cost_collator(
    tu_tree_node_t *ps_node, UWORD8 u1_chroma_processing_enabled, UWORD8 u1_is_422)
{
    UWORD8 i;

    LWORD64 i8_cost = 0;

    i8_cost += ps_node->s_luma_data.i8_cost;

    if(u1_chroma_processing_enabled)
    {
        for(i = 0; i < u1_is_422 + 1; i++)
        {
            i8_cost += ps_node->as_cb_data[i].i8_cost;
            i8_cost += ps_node->as_cr_data[i].i8_cost;
        }
    }

    return i8_cost;
}

#if !ENABLE_TOP_DOWN_TU_RECURSION
/*!
******************************************************************************
* \if Function name : ihevce_tu_processor \endif
*
* \notes
*    Determines RDO TU Tree using DFS. If the parent is the winner, then all
*    pointers to the children nodes are set to NULL
*    Input : 1. ps_ctxt: Pointer to enc-loop's context. Parts of this structure
*            shall be modified by this function. They include, au1_cu_csbf,
*            i8_cu_not_coded_cost, ai2_scratch, s_rdoq_sbh_ctxt,
*            pi4_quant_round_factor_tu_0_1, pi4_quant_round_factor_tu_1_2,
*            i4_quant_round_tu
*            2. ps_node: Pointer to current node of the TU tree. This struct
*            shall be modified by this function
*            3. pv_recon: Pointer to buffer which stores the recon
*            This buffer shall be modified by this function
*            4. ps_nbr_data_buf: Pointer to struct used by succeeding CU's
*            during RDOPT. This buffer shall be modifie by this function
*            6. pi2_deq_data: Pointer to buffer which stores the output of IQ.
*            This buffer shall be modified by this function
*            7. pu1_ecd: Pointer to buffer which stores the data output by
*            entropy coding. This buffer shall be modified by this function
*            8. pu1_cabac_ctxt: Pointer to buffer which stores the current CABAC
*            state. This buffer shall be modified by this function
*    Output : Cost of coding the current branch of the TU tree
*
*****************************************************************************
*/
LWORD64 ihevce_tu_tree_selector(
    ihevce_enc_loop_ctxt_t *ps_ctxt,
    tu_tree_node_t *ps_node,
    buffer_data_for_tu_t *ps_buffer_data,
    UWORD8 *pu1_cabac_ctxt,
    WORD32 i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
    WORD32 i4_alpha_stim_multiplier,
    UWORD8 u1_is_cu_noisy,
#endif
    UWORD8 u1_cur_depth,
    UWORD8 u1_max_depth,
    UWORD8 u1_part_type,
    UWORD8 u1_compute_spatial_ssd)
{
    UWORD8 au1_cabac_ctxt_backup[IHEVC_CAB_CTXT_END];
    UWORD8 u1_are_children_available;
    UWORD32 u4_tuSplitFlag_and_cbf_coding_bits;

    nbr_4x4_t *ps_nbr_data_buf = ps_buffer_data->ps_nbr_data_buf;
    void *pv_recon_chroma = ps_buffer_data->s_src_pred_rec_buf_chroma.pv_recon;
    WORD16 *pi2_deq_data = ps_buffer_data->pi2_deq_data;
    WORD16 *pi2_deq_data_chroma = ps_buffer_data->pi2_deq_data_chroma;
    UWORD8 **ppu1_ecd = ps_buffer_data->ppu1_ecd;
    WORD32 i4_nbr_data_buf_stride = ps_buffer_data->i4_nbr_data_buf_stride;
    WORD32 i4_recon_stride = ps_buffer_data->s_src_pred_rec_buf_luma.i4_recon_stride;
    WORD32 i4_recon_stride_chroma = ps_buffer_data->s_src_pred_rec_buf_chroma.i4_recon_stride;
    WORD32 i4_deq_data_stride = ps_buffer_data->i4_deq_data_stride;
    WORD32 i4_deq_data_stride_chroma = ps_buffer_data->i4_deq_data_stride_chroma;
    UWORD8 *pu1_ecd_bPtr_backup_t1 = ppu1_ecd[0];
    UWORD8 *pu1_ecd_bPtr_backup_t2 = ppu1_ecd[0];
    LWORD64 i8_winning_cost = 0;

    ASSERT(ps_node != NULL);
    ASSERT(
        !(!ps_node->u1_is_valid_node &&
          ((NULL == ps_node->ps_child_node_tl) || (NULL == ps_node->ps_child_node_tr) ||
           (NULL == ps_node->ps_child_node_bl) || (NULL == ps_node->ps_child_node_br))));

    u1_are_children_available =
        !((NULL == ps_node->ps_child_node_tl) && (NULL == ps_node->ps_child_node_tr) &&
          (NULL == ps_node->ps_child_node_bl) && (NULL == ps_node->ps_child_node_br)) &&
        (ps_node->s_luma_data.u1_size > MIN_TU_SIZE);

    if(u1_are_children_available)
    {
        if(ps_node->u1_is_valid_node)
        {
            memcpy(au1_cabac_ctxt_backup, pu1_cabac_ctxt, sizeof(au1_cabac_ctxt_backup));
        }

        if(i4_pred_mode != PRED_MODE_SKIP)
        {
            u4_tuSplitFlag_and_cbf_coding_bits = ihevce_compute_bits_for_TUSplit_and_cbf(
                ps_node,
                ps_node->ps_child_node_tl,
                pu1_cabac_ctxt,
                MAX_TU_SIZE,
                MIN_TU_SIZE,
                0,
                1,
                i4_pred_mode == PRED_MODE_INTRA,
                (u1_part_type == PART_NxN) && (i4_pred_mode == PRED_MODE_INTRA),
                0,
                0);

            i8_winning_cost += COMPUTE_RATE_COST_CLIP30(
                u4_tuSplitFlag_and_cbf_coding_bits,
                ps_ctxt->i8_cl_ssd_lambda_qf,
                (LAMBDA_Q_SHIFT + CABAC_FRAC_BITS_Q));
        }

        i8_winning_cost += ihevce_tu_tree_selector(
            ps_ctxt,
            ps_node->ps_child_node_tl,
            ps_buffer_data,
            pu1_cabac_ctxt,
            i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
            i4_alpha_stim_multiplier,
            u1_is_cu_noisy,
#endif
            u1_cur_depth,
            u1_max_depth,
            u1_part_type,
            u1_compute_spatial_ssd);

        i8_winning_cost += ihevce_tu_tree_selector(
            ps_ctxt,
            ps_node->ps_child_node_tr,
            ps_buffer_data,
            pu1_cabac_ctxt,
            i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
            i4_alpha_stim_multiplier,
            u1_is_cu_noisy,
#endif
            u1_cur_depth,
            u1_max_depth,
            u1_part_type,
            u1_compute_spatial_ssd);

        i8_winning_cost += ihevce_tu_tree_selector(
            ps_ctxt,
            ps_node->ps_child_node_bl,
            ps_buffer_data,
            pu1_cabac_ctxt,
            i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
            i4_alpha_stim_multiplier,
            u1_is_cu_noisy,
#endif
            u1_cur_depth,
            u1_max_depth,
            u1_part_type,
            u1_compute_spatial_ssd);

        i8_winning_cost += ihevce_tu_tree_selector(
            ps_ctxt,
            ps_node->ps_child_node_br,
            ps_buffer_data,
            pu1_cabac_ctxt,
            i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
            i4_alpha_stim_multiplier,
            u1_is_cu_noisy,
#endif
            u1_cur_depth,
            u1_max_depth,
            u1_part_type,
            u1_compute_spatial_ssd);

        if(ps_node->u1_is_valid_node)
        {
            WORD16 ai2_deq_data_backup[MAX_CU_SIZE * MAX_CU_SIZE];
            UWORD16 au2_recon_backup[MAX_CU_SIZE * MAX_CU_SIZE];

            buffer_data_for_tu_t s_buffer_data = ps_buffer_data[0];

            pu1_ecd_bPtr_backup_t2 = ppu1_ecd[0];
            s_buffer_data.pi2_deq_data = ai2_deq_data_backup;
            s_buffer_data.i4_deq_data_stride = MAX_CU_SIZE;
            s_buffer_data.s_src_pred_rec_buf_luma.pv_recon = au2_recon_backup;
            s_buffer_data.s_src_pred_rec_buf_luma.i4_recon_stride = MAX_CU_SIZE;

            ihevce_tu_processor(
                ps_ctxt,
                ps_node,
                &s_buffer_data,
                au1_cabac_ctxt_backup,
                i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
                i4_alpha_stim_multiplier,
                u1_is_cu_noisy,
#endif
                0,
                u1_compute_spatial_ssd);

            if(i4_pred_mode != PRED_MODE_SKIP)
            {
                u4_tuSplitFlag_and_cbf_coding_bits = ihevce_compute_bits_for_TUSplit_and_cbf(
                    ps_node,
                    ps_node,
                    au1_cabac_ctxt_backup,
                    MAX_TU_SIZE,
                    MIN_TU_SIZE,
                    0,
                    (u1_cur_depth == u1_max_depth) ? 0 : 1,
                    i4_pred_mode == PRED_MODE_INTRA,
                    (u1_part_type == PART_NxN) && (i4_pred_mode == PRED_MODE_INTRA),
                    0,
                    0);

                ps_node->s_luma_data.i8_cost += COMPUTE_RATE_COST_CLIP30(
                    u4_tuSplitFlag_and_cbf_coding_bits,
                    ps_ctxt->i8_cl_ssd_lambda_qf,
                    (LAMBDA_Q_SHIFT + CABAC_FRAC_BITS_Q));
            }

            if(ps_node->s_luma_data.i8_cost <= i8_winning_cost)
            {
                ihevce_debriefer_when_parent_wins(
                    ps_node,
                    ps_ctxt->s_cmn_opt_func.pf_copy_2d,
                    ps_ctxt->s_cmn_opt_func.pf_chroma_interleave_2d_copy,
                    ps_nbr_data_buf,
                    ai2_deq_data_backup,
                    pi2_deq_data,
                    ai2_deq_data_backup + MAX_CU_SIZE * MAX_CU_SIZE,
                    pi2_deq_data_chroma,
                    au2_recon_backup,
                    pv_recon_chroma,
                    au2_recon_backup + MAX_CU_SIZE * MAX_CU_SIZE,
                    pv_recon_chroma,
                    au1_cabac_ctxt_backup,
                    pu1_cabac_ctxt,
                    pu1_ecd_bPtr_backup_t2,
                    pu1_ecd_bPtr_backup_t1,
                    i4_nbr_data_buf_stride,
                    MAX_CU_SIZE,
                    i4_deq_data_stride,
                    MAX_CU_SIZE,
                    i4_deq_data_stride_chroma,
                    MAX_CU_SIZE,
                    i4_recon_stride,
                    MAX_CU_SIZE,
                    i4_recon_stride_chroma,
                    sizeof(au1_cabac_ctxt_backup),
                    ps_ctxt->i4_cu_qp,
                    0,
                    ps_ctxt->u1_chroma_array_type == 2,
                    ps_ctxt->u1_bit_depth > 8);

                ppu1_ecd[0] =
                    pu1_ecd_bPtr_backup_t1 + ps_node->s_luma_data.i4_num_bytes_used_for_ecd;
                i8_winning_cost = ps_node->s_luma_data.i8_cost;
            }
            else
            {
                ps_node->u1_is_valid_node = 0;
            }
        }
    }
    else
    {
        ASSERT(ps_node->u1_is_valid_node);

        ihevce_tu_processor(
            ps_ctxt,
            ps_node,
            ps_buffer_data,
            pu1_cabac_ctxt,
            i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
            i4_alpha_stim_multiplier,
            u1_is_cu_noisy,
#endif
            0,
            u1_compute_spatial_ssd);

        if(i4_pred_mode != PRED_MODE_SKIP)
        {
            u4_tuSplitFlag_and_cbf_coding_bits = ihevce_compute_bits_for_TUSplit_and_cbf(
                ps_node,
                ps_node,
                pu1_cabac_ctxt,
                MAX_TU_SIZE,
                MIN_TU_SIZE,
                0,
                (u1_cur_depth == u1_max_depth) ? 0 : 1,
                i4_pred_mode == PRED_MODE_INTRA,
                (u1_part_type == PART_NxN) && (i4_pred_mode == PRED_MODE_INTRA),
                0,
                0);

            ps_node->s_luma_data.i8_cost += COMPUTE_RATE_COST_CLIP30(
                u4_tuSplitFlag_and_cbf_coding_bits,
                ps_ctxt->i8_cl_ssd_lambda_qf,
                (LAMBDA_Q_SHIFT + CABAC_FRAC_BITS_Q));
        }

        ppu1_ecd[0] = pu1_ecd_bPtr_backup_t1 + ps_node->s_luma_data.i4_num_bytes_used_for_ecd;

        ihevce_nbr_data_copier(
            ps_nbr_data_buf,
            i4_nbr_data_buf_stride,
            ps_ctxt->i4_cu_qp,
            ps_node->s_luma_data.u1_cbf,
            ps_node->s_luma_data.u1_posx,
            ps_node->s_luma_data.u1_posy,
            ps_node->s_luma_data.u1_size);

        i8_winning_cost = ps_node->s_luma_data.i8_cost;
    }

    return i8_winning_cost;
}
#endif

/*!
******************************************************************************
* \if Function name : ihevce_topDown_tu_tree_selector \endif
*
* \notes
*    Determines RDO TU Tree using DFS. If the parent is the winner, then all
*    pointers to the children nodes are set to NULL
*    Input : 1. ps_ctxt: Pointer to enc-loop's context. Parts of this structure
*            shall be modified by this function. They include, au1_cu_csbf,
*            i8_cu_not_coded_cost, ai2_scratch, s_rdoq_sbh_ctxt,
*            pi4_quant_round_factor_tu_0_1, pi4_quant_round_factor_tu_1_2,
*            i4_quant_round_tu
*            2. ps_node: Pointer to current node of the TU tree. This struct
*            shall be modified by this function
*            3. pv_recon: Pointer to buffer which stores the recon
*            This buffer shall be modified by this function
*            4. ps_nbr_data_buf: Pointer to struct used by succeeding CU's
*            during RDOPT. This buffer shall be modifie by this function
*            6. pi2_deq_data: Pointer to buffer which stores the output of IQ.
*            This buffer shall be modified by this function
*            7. pu1_ecd: Pointer to buffer which stores the data output by
*            entropy coding. This buffer shall be modified by this function
*            8. pu1_cabac_ctxt: Pointer to buffer which stores the current CABAC
*            state. This buffer shall be modified by this function
*    Output : Cost of coding the current branch of the TU tree
*
*****************************************************************************
*/
LWORD64 ihevce_topDown_tu_tree_selector(
    ihevce_enc_loop_ctxt_t *ps_ctxt,
    tu_tree_node_t *ps_node,
    buffer_data_for_tu_t *ps_buffer_data,
    UWORD8 *pu1_cabac_ctxt,
    WORD32 i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
    WORD32 i4_alpha_stim_multiplier,
    UWORD8 u1_is_cu_noisy,
#endif
    UWORD8 u1_cur_depth,
    UWORD8 u1_max_depth,
    UWORD8 u1_part_type,
    UWORD8 u1_chroma_processing_enabled,
    UWORD8 u1_compute_spatial_ssd)
{
    UWORD8 au1_cabac_ctxt_backup[IHEVC_CAB_CTXT_END];
    UWORD8 u1_are_children_available;
    UWORD32 u4_tuSplitFlag_and_cbf_coding_bits;

    nbr_4x4_t *ps_nbr_data_buf = ps_buffer_data->ps_nbr_data_buf;

    void *pv_recon = ps_buffer_data->s_src_pred_rec_buf_luma.pv_recon;
    void *pv_recon_chroma = ps_buffer_data->s_src_pred_rec_buf_chroma.pv_recon;
    WORD16 *pi2_deq_data = ps_buffer_data->pi2_deq_data;
    WORD16 *pi2_deq_data_chroma = ps_buffer_data->pi2_deq_data_chroma;
    UWORD8 **ppu1_ecd = ps_buffer_data->ppu1_ecd;
    WORD32 i4_nbr_data_buf_stride = ps_buffer_data->i4_nbr_data_buf_stride;
    WORD32 i4_recon_stride = ps_buffer_data->s_src_pred_rec_buf_luma.i4_recon_stride;
    WORD32 i4_recon_stride_chroma = ps_buffer_data->s_src_pred_rec_buf_chroma.i4_recon_stride;
    WORD32 i4_deq_data_stride = ps_buffer_data->i4_deq_data_stride;
    WORD32 i4_deq_data_stride_chroma = ps_buffer_data->i4_deq_data_stride_chroma;
    UWORD8 *pu1_ecd_bPtr_backup_t1 = ppu1_ecd[0];
    UWORD8 *pu1_ecd_bPtr_backup_t2 = ppu1_ecd[0];
    LWORD64 i8_parent_cost = 0;
    LWORD64 i8_child_cost = 0;
    LWORD64 i8_winning_cost = 0;
    UWORD8 u1_is_422 = (ps_ctxt->u1_chroma_array_type == 2);

    ASSERT(ps_node != NULL);
    ASSERT(
        !(!ps_node->u1_is_valid_node &&
          ((NULL == ps_node->ps_child_node_tl) || (NULL == ps_node->ps_child_node_tr) ||
           (NULL == ps_node->ps_child_node_bl) || (NULL == ps_node->ps_child_node_br))));

    u1_are_children_available =
        !((NULL == ps_node->ps_child_node_tl) && (NULL == ps_node->ps_child_node_tr) &&
          (NULL == ps_node->ps_child_node_bl) && (NULL == ps_node->ps_child_node_br)) &&
        (ps_node->s_luma_data.u1_size > MIN_TU_SIZE);

    if(u1_are_children_available)
    {
        WORD16 ai2_deq_data_backup[MAX_CU_SIZE * MAX_CU_SIZE * 2];
        UWORD16 au2_recon_backup[MAX_CU_SIZE * MAX_CU_SIZE * 2];

        UWORD8 u1_is_tu_coded = 0;

        if(ps_node->u1_is_valid_node)
        {
            buffer_data_for_tu_t s_buffer_data = ps_buffer_data[0];

            memcpy(au1_cabac_ctxt_backup, pu1_cabac_ctxt, sizeof(au1_cabac_ctxt_backup));

            s_buffer_data.pi2_deq_data = ai2_deq_data_backup;
            s_buffer_data.i4_deq_data_stride = MAX_CU_SIZE;
            s_buffer_data.pi2_deq_data_chroma = ai2_deq_data_backup + MAX_CU_SIZE * MAX_CU_SIZE;
            s_buffer_data.i4_deq_data_stride_chroma = MAX_CU_SIZE;
            s_buffer_data.s_src_pred_rec_buf_luma.pv_recon = au2_recon_backup;
            s_buffer_data.s_src_pred_rec_buf_luma.i4_recon_stride = MAX_CU_SIZE;
            s_buffer_data.s_src_pred_rec_buf_chroma.pv_recon =
                au2_recon_backup + MAX_CU_SIZE * MAX_CU_SIZE;
            s_buffer_data.s_src_pred_rec_buf_chroma.i4_recon_stride = MAX_CU_SIZE;

            ihevce_tu_processor(
                ps_ctxt,
                ps_node,
                &s_buffer_data,
                au1_cabac_ctxt_backup,
                i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
                i4_alpha_stim_multiplier,
                u1_is_cu_noisy,
#endif
                u1_chroma_processing_enabled,
                u1_compute_spatial_ssd);

            if(i4_pred_mode != PRED_MODE_SKIP)
            {
                u4_tuSplitFlag_and_cbf_coding_bits = ihevce_compute_bits_for_TUSplit_and_cbf(
                    ps_node,
                    ps_node,
                    au1_cabac_ctxt_backup,
                    MAX_TU_SIZE,
                    MIN_TU_SIZE,
                    0,
                    (u1_cur_depth == u1_max_depth) ? 0 : 1,
                    i4_pred_mode == PRED_MODE_INTRA,
                    (u1_part_type == PART_NxN) && (i4_pred_mode == PRED_MODE_INTRA),
                    u1_chroma_processing_enabled,
                    u1_is_422);

                ps_node->s_luma_data.i8_cost += COMPUTE_RATE_COST_CLIP30(
                    u4_tuSplitFlag_and_cbf_coding_bits,
                    ps_ctxt->i8_cl_ssd_lambda_qf,
                    (LAMBDA_Q_SHIFT + CABAC_FRAC_BITS_Q));
            }

            i8_parent_cost +=
                ihevce_tu_node_cost_collator(ps_node, u1_chroma_processing_enabled, u1_is_422);

            ihevce_ecd_buffer_pointer_updater(
                ps_node,
                ppu1_ecd,
                pu1_ecd_bPtr_backup_t1,
                1,
                u1_chroma_processing_enabled,
                u1_is_422);
        }
        else
        {
            ps_node->s_luma_data.i8_cost = i8_parent_cost = LLONG_MAX;
            ps_node->s_luma_data.i4_num_bytes_used_for_ecd = 0;
        }

        u1_is_tu_coded |= ps_node->s_luma_data.u1_cbf;

        if(u1_chroma_processing_enabled)
        {
            UWORD8 i;

            for(i = 0; i < u1_is_422 + 1; i++)
            {
                u1_is_tu_coded |= ps_node->as_cb_data[i].u1_cbf;
                u1_is_tu_coded |= ps_node->as_cr_data[i].u1_cbf;
            }
        }

        if(!ps_node->u1_is_valid_node || u1_is_tu_coded)
        {
            pu1_ecd_bPtr_backup_t2 = ppu1_ecd[0];

            if(i4_pred_mode != PRED_MODE_SKIP)
            {
                u4_tuSplitFlag_and_cbf_coding_bits = ihevce_compute_bits_for_TUSplit_and_cbf(
                    ps_node,
                    ps_node->ps_child_node_tl,
                    pu1_cabac_ctxt,
                    MAX_TU_SIZE,
                    MIN_TU_SIZE,
                    0,
                    1,
                    i4_pred_mode == PRED_MODE_INTRA,
                    (u1_part_type == PART_NxN) && (i4_pred_mode == PRED_MODE_INTRA),
                    u1_chroma_processing_enabled,
                    u1_is_422);

                i8_child_cost += COMPUTE_RATE_COST_CLIP30(
                    u4_tuSplitFlag_and_cbf_coding_bits,
                    ps_ctxt->i8_cl_ssd_lambda_qf,
                    (LAMBDA_Q_SHIFT + CABAC_FRAC_BITS_Q));
            }

            if(i8_child_cost < i8_parent_cost)
            {
                i8_child_cost += ihevce_topDown_tu_tree_selector(
                    ps_ctxt,
                    ps_node->ps_child_node_tl,
                    ps_buffer_data,
                    pu1_cabac_ctxt,
                    i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
                    i4_alpha_stim_multiplier,
                    u1_is_cu_noisy,
#endif
                    u1_cur_depth,
                    u1_max_depth,
                    u1_part_type,
                    u1_chroma_processing_enabled,
                    u1_compute_spatial_ssd);

                ps_node->ps_child_node_tl->s_luma_data.i8_cost +=
                    i8_child_cost - ps_node->ps_child_node_tl->s_luma_data.i8_cost;
            }

            if(i8_child_cost < i8_parent_cost)
            {
                i8_child_cost += ihevce_topDown_tu_tree_selector(
                    ps_ctxt,
                    ps_node->ps_child_node_tr,
                    ps_buffer_data,
                    pu1_cabac_ctxt,
                    i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
                    i4_alpha_stim_multiplier,
                    u1_is_cu_noisy,
#endif
                    u1_cur_depth,
                    u1_max_depth,
                    u1_part_type,
                    u1_chroma_processing_enabled,
                    u1_compute_spatial_ssd);
            }

            if(i8_child_cost < i8_parent_cost)
            {
                i8_child_cost += ihevce_topDown_tu_tree_selector(
                    ps_ctxt,
                    ps_node->ps_child_node_bl,
                    ps_buffer_data,
                    pu1_cabac_ctxt,
                    i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
                    i4_alpha_stim_multiplier,
                    u1_is_cu_noisy,
#endif
                    u1_cur_depth,
                    u1_max_depth,
                    u1_part_type,
                    u1_chroma_processing_enabled,
                    u1_compute_spatial_ssd);
            }

            if(i8_child_cost < i8_parent_cost)
            {
                i8_child_cost += ihevce_topDown_tu_tree_selector(
                    ps_ctxt,
                    ps_node->ps_child_node_br,
                    ps_buffer_data,
                    pu1_cabac_ctxt,
                    i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
                    i4_alpha_stim_multiplier,
                    u1_is_cu_noisy,
#endif
                    u1_cur_depth,
                    u1_max_depth,
                    u1_part_type,
                    u1_chroma_processing_enabled,
                    u1_compute_spatial_ssd);
            }

            if(i8_parent_cost > i8_child_cost)
            {
                UWORD32 u4_num_bytes = ihevce_ecd_buffer_pointer_updater(
                    ps_node,
                    ppu1_ecd,
                    pu1_ecd_bPtr_backup_t1,
                    0,
                    u1_chroma_processing_enabled,
                    u1_is_422);

                if(pu1_ecd_bPtr_backup_t2 != pu1_ecd_bPtr_backup_t1)
                {
                    memmove(pu1_ecd_bPtr_backup_t1, pu1_ecd_bPtr_backup_t2, u4_num_bytes);
                }

                ps_node->s_luma_data.i4_num_bytes_used_for_ecd = u4_num_bytes;
                ps_node->as_cb_data[0].i4_num_bytes_used_for_ecd = 0;
                ps_node->as_cb_data[1].i4_num_bytes_used_for_ecd = 0;
                ps_node->as_cr_data[0].i4_num_bytes_used_for_ecd = 0;
                ps_node->as_cr_data[1].i4_num_bytes_used_for_ecd = 0;

                ps_node->u1_is_valid_node = 0;

                i8_winning_cost = i8_child_cost;
            }
            else
            {
                ihevce_debriefer_when_parent_wins(
                    ps_node,
                    ps_ctxt->s_cmn_opt_func.pf_copy_2d,
                    ps_ctxt->s_cmn_opt_func.pf_chroma_interleave_2d_copy,
                    ps_nbr_data_buf,
                    ai2_deq_data_backup,
                    pi2_deq_data,
                    ai2_deq_data_backup + MAX_CU_SIZE * MAX_CU_SIZE,
                    pi2_deq_data_chroma,
                    au2_recon_backup,
                    pv_recon,
                    au2_recon_backup + MAX_CU_SIZE * MAX_CU_SIZE,
                    pv_recon_chroma,
                    au1_cabac_ctxt_backup,
                    pu1_cabac_ctxt,
                    NULL,
                    NULL,
                    i4_nbr_data_buf_stride,
                    MAX_CU_SIZE,
                    i4_deq_data_stride,
                    MAX_CU_SIZE,
                    i4_deq_data_stride_chroma,
                    MAX_CU_SIZE,
                    i4_recon_stride,
                    MAX_CU_SIZE,
                    i4_recon_stride_chroma,
                    sizeof(au1_cabac_ctxt_backup),
                    ps_ctxt->i4_cu_qp,
                    u1_chroma_processing_enabled,
                    u1_is_422,
                    ps_ctxt->u1_bit_depth > 8);

                ihevce_ecd_buffer_pointer_updater(
                    ps_node,
                    ppu1_ecd,
                    pu1_ecd_bPtr_backup_t1,
                    1,
                    u1_chroma_processing_enabled,
                    u1_is_422);

                i8_winning_cost = i8_parent_cost;
            }
        }
        else
        {
            ihevce_debriefer_when_parent_wins(
                ps_node,
                ps_ctxt->s_cmn_opt_func.pf_copy_2d,
                ps_ctxt->s_cmn_opt_func.pf_chroma_interleave_2d_copy,
                ps_nbr_data_buf,
                ai2_deq_data_backup,
                pi2_deq_data,
                ai2_deq_data_backup + MAX_CU_SIZE * MAX_CU_SIZE,
                pi2_deq_data_chroma,
                au2_recon_backup,
                pv_recon,
                au2_recon_backup + MAX_CU_SIZE * MAX_CU_SIZE,
                pv_recon_chroma,
                au1_cabac_ctxt_backup,
                pu1_cabac_ctxt,
                NULL,
                NULL,
                i4_nbr_data_buf_stride,
                MAX_CU_SIZE,
                i4_deq_data_stride,
                MAX_CU_SIZE,
                i4_deq_data_stride_chroma,
                MAX_CU_SIZE,
                i4_recon_stride,
                MAX_CU_SIZE,
                i4_recon_stride_chroma,
                sizeof(au1_cabac_ctxt_backup),
                ps_ctxt->i4_cu_qp,
                u1_chroma_processing_enabled,
                u1_is_422,
                ps_ctxt->u1_bit_depth > 8);

            ihevce_ecd_buffer_pointer_updater(
                ps_node,
                ppu1_ecd,
                pu1_ecd_bPtr_backup_t1,
                1,
                u1_chroma_processing_enabled,
                u1_is_422);

            i8_winning_cost = i8_parent_cost;
        }
    }
    else
    {
        ASSERT(ps_node->u1_is_valid_node);

        ihevce_tu_processor(
            ps_ctxt,
            ps_node,
            ps_buffer_data,
            pu1_cabac_ctxt,
            i4_pred_mode,
#if USE_NOISE_TERM_IN_ZERO_CODING_DECISION_ALGORITHMS
            i4_alpha_stim_multiplier,
            u1_is_cu_noisy,
#endif
            u1_chroma_processing_enabled,
            u1_compute_spatial_ssd);

        if(i4_pred_mode != PRED_MODE_SKIP)
        {
            u4_tuSplitFlag_and_cbf_coding_bits = ihevce_compute_bits_for_TUSplit_and_cbf(
                ps_node,
                ps_node,
                pu1_cabac_ctxt,
                MAX_TU_SIZE,
                MIN_TU_SIZE,
                0,
                (u1_cur_depth == u1_max_depth) ? 0 : 1,
                i4_pred_mode == PRED_MODE_INTRA,
                (u1_part_type == PART_NxN) && (i4_pred_mode == PRED_MODE_INTRA),
                u1_chroma_processing_enabled,
                u1_is_422);

            ps_node->s_luma_data.i8_cost += COMPUTE_RATE_COST_CLIP30(
                u4_tuSplitFlag_and_cbf_coding_bits,
                ps_ctxt->i8_cl_ssd_lambda_qf,
                (LAMBDA_Q_SHIFT + CABAC_FRAC_BITS_Q));
        }

        i8_winning_cost +=
            ihevce_tu_node_cost_collator(ps_node, u1_chroma_processing_enabled, u1_is_422);

        ihevce_ecd_buffer_pointer_updater(
            ps_node, ppu1_ecd, pu1_ecd_bPtr_backup_t1, 1, u1_chroma_processing_enabled, u1_is_422);

        ihevce_nbr_data_copier(
            ps_nbr_data_buf,
            i4_nbr_data_buf_stride,
            ps_ctxt->i4_cu_qp,
            ps_node->s_luma_data.u1_cbf,
            ps_node->s_luma_data.u1_posx,
            ps_node->s_luma_data.u1_posy,
            ps_node->s_luma_data.u1_size);
    }

    return i8_winning_cost;
}

/*!
******************************************************************************
* \if Function name : ihevce_tu_selector_debriefer \endif
*
* \notes
*    Conversion of TU Tree struct into TU info array. Collection of myriad CU
*    level data
*    Input : 1. ps_node: Pointer to current node of the TU tree. This struct
*            shall be modified by this function
*            2. ps_final_prms: Pointer to struct that stores RDOPT output data.
*            This buffer shall be modified by this function
*    Output : 1. pi8_total_cost: Total CU-level cost
*             2. pi8_total_non_coded_cost: Total CU level cost when no residue
*             is coded
*             3. pi4_num_bytes_used_for_ecd: Number of bytes used for storing
*             entropy coding data
*             4. pi4_num_bits_used_for_encoding: Number of bits used for encoding
*             5. pu2_tu_ctr: Number of TU's in the CU
*
*****************************************************************************
*/
void ihevce_tu_selector_debriefer(
    tu_tree_node_t *ps_node,
    enc_loop_cu_final_prms_t *ps_final_prms,
    LWORD64 *pi8_total_cost,
    LWORD64 *pi8_total_non_coded_cost,
    WORD32 *pi4_num_bytes_used_for_ecd,
    WORD32 *pi4_num_bits_used_for_encoding,
    UWORD16 *pu2_tu_ctr,
    WORD32 i4_cu_qp,
    UWORD8 u1_cu_posx,
    UWORD8 u1_cu_posy,
    UWORD8 u1_chroma_processing_enabled,
    UWORD8 u1_is_422,
    TU_POS_T e_tu_pos)
{
    UWORD8 u1_is_chroma_tu_valid = 1;
    WORD32 i4_log2_size;

    ASSERT(ps_node != NULL);

    if(ps_node->u1_is_valid_node)
    {
        ASSERT(
            (NULL == ps_node->ps_child_node_tl) && (NULL == ps_node->ps_child_node_tr) &&
            (NULL == ps_node->ps_child_node_bl) && (NULL == ps_node->ps_child_node_br));
    }
    else
    {
        ASSERT(
            !((NULL == ps_node->ps_child_node_tl) || (NULL == ps_node->ps_child_node_tr) ||
              (NULL == ps_node->ps_child_node_bl) || (NULL == ps_node->ps_child_node_br)));
    }

    if(ps_node->u1_is_valid_node)
    {
        if((4 == ps_node->s_luma_data.u1_size) && (POS_TL != e_tu_pos))
        {
            u1_is_chroma_tu_valid = INTRA_PRED_CHROMA_IDX_NONE;
        }

        GETRANGE(i4_log2_size, ps_node->s_luma_data.u1_size);

        ps_final_prms->s_recon_datastore.au1_bufId_with_winning_LumaRecon[pu2_tu_ctr[0]] =
            ps_node->s_luma_data.u1_reconBufId;
        ps_final_prms->u4_cu_sad += ps_node->s_luma_data.u4_sad;
        ps_final_prms->u1_is_cu_coded |= ps_node->s_luma_data.u1_cbf;
        ps_final_prms->u4_cu_luma_res_bits += ps_node->s_luma_data.i4_bits;

        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].i4_luma_coeff_offset =
            pi4_num_bytes_used_for_ecd[0];
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_y_cbf = ps_node->s_luma_data.u1_cbf;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_cb_cbf = 0;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_cr_cbf = 0;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_cb_cbf_subtu1 = 0;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_cr_cbf_subtu1 = 0;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b3_chroma_intra_mode_idx =
            u1_is_chroma_tu_valid;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b7_qp = i4_cu_qp;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_first_tu_in_cu =
            (!ps_node->s_luma_data.u1_posx && !ps_node->s_luma_data.u1_posx);
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_transquant_bypass = 0;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b3_size = i4_log2_size - 3;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b4_pos_x =
            (u1_cu_posx + ps_node->s_luma_data.u1_posx) / 4;
        ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b4_pos_y =
            (u1_cu_posy + ps_node->s_luma_data.u1_posy) / 4;

        ps_final_prms->as_tu_enc_loop_temp_prms[pu2_tu_ctr[0]].i2_luma_bytes_consumed =
            ps_node->s_luma_data.i4_num_bytes_used_for_ecd;
        ps_final_prms->as_tu_enc_loop_temp_prms[pu2_tu_ctr[0]].u4_luma_zero_col =
            ps_node->s_luma_data.i4_zero_col;
        ps_final_prms->as_tu_enc_loop_temp_prms[pu2_tu_ctr[0]].u4_luma_zero_row =
            ps_node->s_luma_data.i4_zero_row;

        pi8_total_cost[0] += ps_node->s_luma_data.i8_cost;
        pi8_total_non_coded_cost[0] += ps_node->s_luma_data.i8_not_coded_cost;
        pi4_num_bytes_used_for_ecd[0] += ps_node->s_luma_data.i4_num_bytes_used_for_ecd;
        pi4_num_bits_used_for_encoding[0] += ps_node->s_luma_data.i4_bits;

        if(u1_chroma_processing_enabled)
        {
            UWORD8 i;

            for(i = 0; i < u1_is_422 + 1; i++)
            {
                ps_final_prms->s_recon_datastore
                    .au1_bufId_with_winning_ChromaRecon[U_PLANE][pu2_tu_ctr[0]][i] =
                    ps_node->as_cb_data[i].u1_reconBufId;
                ps_final_prms->u1_is_cu_coded |= ps_node->as_cb_data[i].u1_cbf;
                ps_final_prms->u4_cu_chroma_res_bits += ps_node->as_cb_data[i].i4_bits;

                ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].ai4_cb_coeff_offset[i] =
                    pi4_num_bytes_used_for_ecd[0];

                if(!i)
                {
                    ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_cb_cbf =
                        ps_node->as_cb_data[i].u1_cbf;
                }
                else
                {
                    ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_cb_cbf_subtu1 =
                        ps_node->as_cb_data[i].u1_cbf;
                }

                ps_final_prms->as_tu_enc_loop_temp_prms[pu2_tu_ctr[0]].ai2_cb_bytes_consumed[i] =
                    ps_node->as_cb_data[i].i4_num_bytes_used_for_ecd;
                ps_final_prms->as_tu_enc_loop_temp_prms[pu2_tu_ctr[0]].au4_cb_zero_col[i] =
                    ps_node->as_cb_data[i].i4_zero_col;
                ps_final_prms->as_tu_enc_loop_temp_prms[pu2_tu_ctr[0]].au4_cb_zero_row[i] =
                    ps_node->as_cb_data[i].i4_zero_row;

                pi8_total_cost[0] += ps_node->as_cb_data[i].i8_cost;
                pi8_total_non_coded_cost[0] += ps_node->as_cb_data[i].i8_not_coded_cost;
                pi4_num_bytes_used_for_ecd[0] += ps_node->as_cb_data[i].i4_num_bytes_used_for_ecd;
                pi4_num_bits_used_for_encoding[0] += ps_node->as_cb_data[i].i4_bits;
            }

            for(i = 0; i < u1_is_422 + 1; i++)
            {
                ps_final_prms->s_recon_datastore
                    .au1_bufId_with_winning_ChromaRecon[V_PLANE][pu2_tu_ctr[0]][i] =
                    ps_node->as_cr_data[i].u1_reconBufId;
                ps_final_prms->u1_is_cu_coded |= ps_node->as_cr_data[i].u1_cbf;
                ps_final_prms->u4_cu_chroma_res_bits += ps_node->as_cr_data[i].i4_bits;

                ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].ai4_cr_coeff_offset[i] =
                    pi4_num_bytes_used_for_ecd[0];

                if(!i)
                {
                    ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_cr_cbf =
                        ps_node->as_cr_data[i].u1_cbf;
                }
                else
                {
                    ps_final_prms->as_tu_enc_loop[pu2_tu_ctr[0]].s_tu.b1_cr_cbf_subtu1 =
                        ps_node->as_cr_data[i].u1_cbf;
                }

                ps_final_prms->as_tu_enc_loop_temp_prms[pu2_tu_ctr[0]].ai2_cr_bytes_consumed[i] =
                    ps_node->as_cr_data[i].i4_num_bytes_used_for_ecd;
                ps_final_prms->as_tu_enc_loop_temp_prms[pu2_tu_ctr[0]].au4_cr_zero_col[i] =
                    ps_node->as_cr_data[i].i4_zero_col;
                ps_final_prms->as_tu_enc_loop_temp_prms[pu2_tu_ctr[0]].au4_cr_zero_row[i] =
                    ps_node->as_cr_data[i].i4_zero_row;

                pi8_total_cost[0] += ps_node->as_cr_data[i].i8_cost;
                pi8_total_non_coded_cost[0] += ps_node->as_cr_data[i].i8_not_coded_cost;
                pi4_num_bytes_used_for_ecd[0] += ps_node->as_cr_data[i].i4_num_bytes_used_for_ecd;
                pi4_num_bits_used_for_encoding[0] += ps_node->as_cr_data[i].i4_bits;
            }
        }

        pu2_tu_ctr[0]++;
    }
    else
    {
        ihevce_tu_selector_debriefer(
            ps_node->ps_child_node_tl,
            ps_final_prms,
            pi8_total_cost,
            pi8_total_non_coded_cost,
            pi4_num_bytes_used_for_ecd,
            pi4_num_bits_used_for_encoding,
            pu2_tu_ctr,
            i4_cu_qp,
            u1_cu_posx,
            u1_cu_posy,
            u1_chroma_processing_enabled,
            u1_is_422,
            POS_TL);

        ihevce_tu_selector_debriefer(
            ps_node->ps_child_node_tr,
            ps_final_prms,
            pi8_total_cost,
            pi8_total_non_coded_cost,
            pi4_num_bytes_used_for_ecd,
            pi4_num_bits_used_for_encoding,
            pu2_tu_ctr,
            i4_cu_qp,
            u1_cu_posx,
            u1_cu_posy,
            u1_chroma_processing_enabled,
            u1_is_422,
            POS_TR);

        ihevce_tu_selector_debriefer(
            ps_node->ps_child_node_bl,
            ps_final_prms,
            pi8_total_cost,
            pi8_total_non_coded_cost,
            pi4_num_bytes_used_for_ecd,
            pi4_num_bits_used_for_encoding,
            pu2_tu_ctr,
            i4_cu_qp,
            u1_cu_posx,
            u1_cu_posy,
            u1_chroma_processing_enabled,
            u1_is_422,
            POS_BL);

        ihevce_tu_selector_debriefer(
            ps_node->ps_child_node_br,
            ps_final_prms,
            pi8_total_cost,
            pi8_total_non_coded_cost,
            pi4_num_bytes_used_for_ecd,
            pi4_num_bits_used_for_encoding,
            pu2_tu_ctr,
            i4_cu_qp,
            u1_cu_posx,
            u1_cu_posy,
            u1_chroma_processing_enabled,
            u1_is_422,
            POS_BR);
    }
}

static UWORD8 ihevce_get_curTUSplit_from_TUSplitArray(
    WORD32 ai4_tuSplitArray[4], UWORD8 u1_cu_size, UWORD8 u1_tu_size, UWORD8 u1_posx, UWORD8 u1_posy)
{
    UWORD8 u1_is_split = 0;

    UWORD8 u1_tuSplitArrayIndex = 0;
    UWORD8 u1_bit_index = 0;

    switch(u1_cu_size)
    {
    case 8:
    {
        switch(u1_tu_size)
        {
        case 8:
        {
            u1_is_split = !!(ai4_tuSplitArray[u1_tuSplitArrayIndex] & BIT_EN(u1_bit_index));

            break;
        }
        case 4:
        {
            u1_is_split = 0;

            break;
        }
        }

        break;
    }
    case 16:
    {
        switch(u1_tu_size)
        {
        case 16:
        {
            u1_is_split = !!(ai4_tuSplitArray[u1_tuSplitArrayIndex] & BIT_EN(u1_bit_index));

            break;
        }
        case 8:
        {
            u1_bit_index += ((u1_posx / 8) % 2) + 2 * ((u1_posy / 8) % 2) + 1;
            u1_is_split = !!(ai4_tuSplitArray[u1_tuSplitArrayIndex] & BIT_EN(u1_bit_index));

            break;
        }
        case 4:
        {
            u1_is_split = 0;

            break;
        }
        }

        break;
    }
    case 32:
    {
        switch(u1_tu_size)
        {
        case 32:
        {
            u1_is_split = !!(ai4_tuSplitArray[u1_tuSplitArrayIndex] & BIT_EN(u1_bit_index));

            break;
        }
        case 16:
        {
            u1_bit_index += 5 * ((u1_posx / 16) % 2) + 10 * ((u1_posy / 16) % 2) + 1;
            u1_is_split = !!(ai4_tuSplitArray[u1_tuSplitArrayIndex] & BIT_EN(u1_bit_index));

            break;
        }
        case 8:
        {
            u1_bit_index = 5 * ((u1_posx / 16) % 2) + 10 * ((u1_posy / 16) % 2) + 1;
            u1_bit_index += ((u1_posx / 8) % 2) + 2 * ((u1_posy / 8) % 2) + 1;
            u1_is_split = !!(ai4_tuSplitArray[u1_tuSplitArrayIndex] & BIT_EN(u1_bit_index));

            break;
        }
        case 4:
        {
            u1_is_split = 0;

            break;
        }
        }

        break;
    }
    case 64:
    {
        switch(u1_tu_size)
        {
        case 64:
        {
            u1_is_split = 1;

            break;
        }
        case 32:
        {
            u1_tuSplitArrayIndex = ((u1_posx / 32) % 2) + 2 * ((u1_posy / 32) % 2);
            u1_is_split = !!(ai4_tuSplitArray[u1_tuSplitArrayIndex] & BIT_EN(u1_bit_index));

            break;
        }
        case 16:
        {
            u1_tuSplitArrayIndex = ((u1_posx / 32) % 2) + 2 * ((u1_posy / 32) % 2);
            u1_bit_index += 5 * ((u1_posx / 16) % 2) + 10 * ((u1_posy / 16) % 2) + 1;
            u1_is_split = !!(ai4_tuSplitArray[u1_tuSplitArrayIndex] & BIT_EN(u1_bit_index));

            break;
        }
        case 8:
        {
            u1_tuSplitArrayIndex = ((u1_posx / 32) % 2) + 2 * ((u1_posy / 32) % 2);
            u1_bit_index += 5 * ((u1_posx / 16) % 2) + 10 * ((u1_posy / 16) % 2) + 1;
            u1_bit_index += ((u1_posx / 8) % 2) + 2 * ((u1_posy / 8) % 2) + 1;
            u1_is_split = !!(ai4_tuSplitArray[u1_tuSplitArrayIndex] & BIT_EN(u1_bit_index));

            break;
        }
        case 4:
        {
            u1_is_split = 0;

            break;
        }
        }

        break;
    }
    }

    return u1_is_split;
}

/*!
******************************************************************************
* \if Function name : ihevce_tuSplitArray_to_tuTree_mapper \endif
*
* \notes
*    This function assumes that ihevce_tu_tree_init' has been called already.
*    The pointers to the children nodes of the leaf-most nodes in the tree
*    are assigned NULL
*    Input : 1. ps_root: Pointer to root of the tree containing TU info.
*            This struct shall be modified by this function
*            2. ai4_tuSplitArray: Array containing information about TU splits
*    Output : 1. TU tree is modified such that it reflects the information
*             coded in ai4_tuSplitArray
*
*****************************************************************************
*/
void ihevce_tuSplitArray_to_tuTree_mapper(
    tu_tree_node_t *ps_root,
    WORD32 ai4_tuSplitArray[4],
    UWORD8 u1_cu_size,
    UWORD8 u1_tu_size,
    UWORD8 u1_min_tu_size,
    UWORD8 u1_max_tu_size,
    UWORD8 u1_is_skip)
{
    UWORD8 u1_is_split;

    ASSERT(u1_min_tu_size >= MIN_TU_SIZE);
    ASSERT(u1_max_tu_size <= MAX_TU_SIZE);
    ASSERT(u1_min_tu_size <= u1_max_tu_size);

    ASSERT(!u1_is_skip);

    ASSERT(ps_root != NULL);
    ASSERT(ps_root->s_luma_data.u1_size == u1_tu_size);

    if(u1_tu_size <= u1_max_tu_size)
    {
        ASSERT(ps_root->u1_is_valid_node);
    }
    else
    {
        ASSERT(!ps_root->u1_is_valid_node);
    }

    if(u1_tu_size > u1_min_tu_size)
    {
        ASSERT(ps_root->ps_child_node_tl != NULL);
        ASSERT(ps_root->ps_child_node_tr != NULL);
        ASSERT(ps_root->ps_child_node_bl != NULL);
        ASSERT(ps_root->ps_child_node_br != NULL);
        ASSERT(ps_root->ps_child_node_tl->s_luma_data.u1_size == (u1_tu_size / 2));
        ASSERT(ps_root->ps_child_node_tr->s_luma_data.u1_size == (u1_tu_size / 2));
        ASSERT(ps_root->ps_child_node_bl->s_luma_data.u1_size == (u1_tu_size / 2));
        ASSERT(ps_root->ps_child_node_br->s_luma_data.u1_size == (u1_tu_size / 2));
        ASSERT(ps_root->ps_child_node_tl->u1_is_valid_node);
        ASSERT(ps_root->ps_child_node_tr->u1_is_valid_node);
        ASSERT(ps_root->ps_child_node_bl->u1_is_valid_node);
        ASSERT(ps_root->ps_child_node_br->u1_is_valid_node);
    }
    else
    {
        ASSERT(ps_root->ps_child_node_tl == NULL);
        ASSERT(ps_root->ps_child_node_tr == NULL);
        ASSERT(ps_root->ps_child_node_bl == NULL);
        ASSERT(ps_root->ps_child_node_br == NULL);
    }

    u1_is_split = ihevce_get_curTUSplit_from_TUSplitArray(
        ai4_tuSplitArray,
        u1_cu_size,
        u1_tu_size,
        ps_root->s_luma_data.u1_posx,
        ps_root->s_luma_data.u1_posy);

    if(u1_tu_size == u1_min_tu_size)
    {
        ASSERT(!u1_is_split);
    }

    if(u1_is_split)
    {
        ps_root->u1_is_valid_node = 0;

        ihevce_tuSplitArray_to_tuTree_mapper(
            ps_root->ps_child_node_tl,
            ai4_tuSplitArray,
            u1_cu_size,
            ps_root->ps_child_node_tl->s_luma_data.u1_size,
            u1_min_tu_size,
            u1_max_tu_size,
            u1_is_skip);

        ihevce_tuSplitArray_to_tuTree_mapper(
            ps_root->ps_child_node_tr,
            ai4_tuSplitArray,
            u1_cu_size,
            ps_root->ps_child_node_tr->s_luma_data.u1_size,
            u1_min_tu_size,
            u1_max_tu_size,
            u1_is_skip);

        ihevce_tuSplitArray_to_tuTree_mapper(
            ps_root->ps_child_node_bl,
            ai4_tuSplitArray,
            u1_cu_size,
            ps_root->ps_child_node_bl->s_luma_data.u1_size,
            u1_min_tu_size,
            u1_max_tu_size,
            u1_is_skip);

        ihevce_tuSplitArray_to_tuTree_mapper(
            ps_root->ps_child_node_br,
            ai4_tuSplitArray,
            u1_cu_size,
            ps_root->ps_child_node_br->s_luma_data.u1_size,
            u1_min_tu_size,
            u1_max_tu_size,
            u1_is_skip);
    }
    else
    {
        ps_root->ps_child_node_tl = NULL;
        ps_root->ps_child_node_tr = NULL;
        ps_root->ps_child_node_bl = NULL;
        ps_root->ps_child_node_br = NULL;
    }
}