blob: c5f5cb4cfe9e11642367b6ef36d474b398ffe07e [file] [log] [blame]
/******************************************************************************
*
* 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;
}
}