blob: c8e6b38a43e882747178121d3b6e33e742b9ba04 [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 hme_refine.c
*
* @brief
* Contains the implementation of the refinement layer searches and related
* functionality like CU merge.
*
* @author
* Ittiam
*
*
* List of Functions
*
*
******************************************************************************
*/
/*****************************************************************************/
/* 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_multi_thrd_funcs.h"
#include "ihevce_me_common_defs.h"
#include "ihevce_had_satd.h"
#include "ihevce_error_codes.h"
#include "ihevce_bitstream.h"
#include "ihevce_cabac.h"
#include "ihevce_rdoq_macros.h"
#include "ihevce_function_selector.h"
#include "ihevce_enc_structs.h"
#include "ihevce_entropy_structs.h"
#include "ihevce_cmn_utils_instr_set_router.h"
#include "ihevce_enc_loop_structs.h"
#include "ihevce_bs_compute_ctb.h"
#include "ihevce_global_tables.h"
#include "ihevce_dep_mngr_interface.h"
#include "hme_datatype.h"
#include "hme_interface.h"
#include "hme_common_defs.h"
#include "hme_defs.h"
#include "ihevce_me_instr_set_router.h"
#include "hme_globals.h"
#include "hme_utils.h"
#include "hme_coarse.h"
#include "hme_fullpel.h"
#include "hme_subpel.h"
#include "hme_refine.h"
#include "hme_err_compute.h"
#include "hme_common_utils.h"
#include "hme_search_algo.h"
#include "ihevce_stasino_helpers.h"
#include "ihevce_common_utils.h"
/*****************************************************************************/
/* Globals */
/*****************************************************************************/
/* brief: mapping buffer to convert raster scan indices into z-scan oder in a ctb */
UWORD8 gau1_raster_scan_to_ctb[4][4] = {
{ 0, 4, 16, 20 }, { 8, 12, 24, 28 }, { 32, 36, 48, 52 }, { 40, 44, 56, 60 }
};
/*****************************************************************************/
/* Extern Fucntion declaration */
/*****************************************************************************/
extern ctb_boundary_attrs_t *
get_ctb_attrs(S32 ctb_start_x, S32 ctb_start_y, S32 pic_wd, S32 pic_ht, me_frm_ctxt_t *ps_ctxt);
typedef void (*PF_HME_PROJECT_COLOC_CANDT_FXN)(
search_node_t *ps_search_node,
layer_ctxt_t *ps_curr_layer,
layer_ctxt_t *ps_coarse_layer,
S32 i4_pos_x,
S32 i4_pos_y,
S08 i1_ref_id,
S32 i4_result_id);
typedef void (*PF_HME_PROJECT_COLOC_CANDT_L0_ME_FXN)(
search_node_t *ps_search_node,
layer_ctxt_t *ps_curr_layer,
layer_ctxt_t *ps_coarse_layer,
S32 i4_pos_x,
S32 i4_pos_y,
S32 i4_num_act_ref_l0,
U08 u1_pred_dir,
U08 u1_default_ref_id,
S32 i4_result_id);
/*****************************************************************************/
/* Function Definitions */
/*****************************************************************************/
void ihevce_no_wt_copy(
coarse_me_ctxt_t *ps_ctxt,
layer_ctxt_t *ps_curr_layer,
pu_t *ps_pu,
UWORD8 *pu1_temp_pred,
WORD32 temp_stride,
WORD32 blk_x,
WORD32 blk_y)
{
UWORD8 *pu1_ref;
WORD32 ref_stride, ref_offset;
WORD32 row, col, i4_tmp;
ASSERT((ps_pu->b2_pred_mode == PRED_L0) || (ps_pu->b2_pred_mode == PRED_L1));
if(ps_pu->b2_pred_mode == PRED_L0)
{
WORD8 i1_ref_idx;
i1_ref_idx = ps_pu->mv.i1_l0_ref_idx;
pu1_ref = ps_curr_layer->ppu1_list_inp[i1_ref_idx];
ref_stride = ps_curr_layer->i4_inp_stride;
ref_offset = ((blk_y << 3) + ps_pu->mv.s_l0_mv.i2_mvy) * ref_stride;
ref_offset += (blk_x << 3) + ps_pu->mv.s_l0_mv.i2_mvx;
pu1_ref += ref_offset;
for(row = 0; row < temp_stride; row++)
{
for(col = 0; col < temp_stride; col++)
{
i4_tmp = pu1_ref[col];
pu1_temp_pred[col] = CLIP_U8(i4_tmp);
}
pu1_ref += ref_stride;
pu1_temp_pred += temp_stride;
}
}
else
{
WORD8 i1_ref_idx;
i1_ref_idx = ps_pu->mv.i1_l1_ref_idx;
pu1_ref = ps_curr_layer->ppu1_list_inp[i1_ref_idx];
ref_stride = ps_curr_layer->i4_inp_stride;
ref_offset = ((blk_y << 3) + ps_pu->mv.s_l1_mv.i2_mvy) * ref_stride;
ref_offset += (blk_x << 3) + ps_pu->mv.s_l1_mv.i2_mvx;
pu1_ref += ref_offset;
for(row = 0; row < temp_stride; row++)
{
for(col = 0; col < temp_stride; col++)
{
i4_tmp = pu1_ref[col];
pu1_temp_pred[col] = CLIP_U8(i4_tmp);
}
pu1_ref += ref_stride;
pu1_temp_pred += temp_stride;
}
}
}
static WORD32 hme_add_clustered_mvs_as_merge_cands(
cluster_data_t *ps_cluster_base,
search_node_t *ps_merge_cand,
range_prms_t **pps_range_prms,
U08 *pu1_refid_to_pred_dir_list,
WORD32 i4_num_clusters,
U08 u1_pred_dir)
{
WORD32 i, j, k;
WORD32 i4_num_cands_added = 0;
WORD32 i4_num_mvs_in_cluster;
for(i = 0; i < i4_num_clusters; i++)
{
cluster_data_t *ps_data = &ps_cluster_base[i];
if(u1_pred_dir == !pu1_refid_to_pred_dir_list[ps_data->ref_id])
{
i4_num_mvs_in_cluster = ps_data->num_mvs;
for(j = 0; j < i4_num_mvs_in_cluster; j++)
{
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvx = ps_data->as_mv[j].mvx;
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvy = ps_data->as_mv[j].mvy;
ps_merge_cand[i4_num_cands_added].i1_ref_idx = ps_data->ref_id;
CLIP_MV_WITHIN_RANGE(
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvx,
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvy,
pps_range_prms[ps_data->ref_id],
0,
0,
0);
for(k = 0; k < i4_num_cands_added; k++)
{
if((ps_merge_cand[k].s_mv.i2_mvx == ps_data->as_mv[j].mvx) &&
(ps_merge_cand[k].s_mv.i2_mvy == ps_data->as_mv[j].mvy) &&
(ps_merge_cand[k].i1_ref_idx == ps_data->ref_id))
{
break;
}
}
if(k == i4_num_cands_added)
{
i4_num_cands_added++;
}
}
}
}
return i4_num_cands_added;
}
static WORD32 hme_add_me_best_as_merge_cands(
search_results_t **pps_child_data_array,
inter_cu_results_t *ps_8x8cu_results,
search_node_t *ps_merge_cand,
range_prms_t **pps_range_prms,
U08 *pu1_refid_to_pred_dir_list,
S08 *pi1_past_list,
S08 *pi1_future_list,
BLK_SIZE_T e_blk_size,
ME_QUALITY_PRESETS_T e_quality_preset,
S32 i4_num_cands_added,
U08 u1_pred_dir)
{
WORD32 i, j, k;
WORD32 i4_max_cands_to_add;
WORD32 i4_result_id = 0;
ASSERT(!pps_child_data_array[0]->u1_split_flag || (BLK_64x64 != e_blk_size));
ASSERT(!pps_child_data_array[1]->u1_split_flag || (BLK_64x64 != e_blk_size));
ASSERT(!pps_child_data_array[2]->u1_split_flag || (BLK_64x64 != e_blk_size));
ASSERT(!pps_child_data_array[3]->u1_split_flag || (BLK_64x64 != e_blk_size));
switch(e_quality_preset)
{
case ME_PRISTINE_QUALITY:
{
i4_max_cands_to_add = MAX_MERGE_CANDTS;
break;
}
case ME_HIGH_QUALITY:
{
/* All 4 children are split and each grandchild contributes an MV */
/* and 2 best results per grandchild */
i4_max_cands_to_add = 4 * 4 * 2;
break;
}
case ME_MEDIUM_SPEED:
{
i4_max_cands_to_add = 4 * 2 * 2;
break;
}
case ME_HIGH_SPEED:
case ME_XTREME_SPEED:
case ME_XTREME_SPEED_25:
{
i4_max_cands_to_add = 4 * 2 * 1;
break;
}
}
while(i4_result_id < 4)
{
for(i = 0; i < 4; i++)
{
inter_cu_results_t *ps_child_data = pps_child_data_array[i]->ps_cu_results;
inter_cu_results_t *ps_grandchild_data = &ps_8x8cu_results[i << 2];
if(!pps_child_data_array[i]->u1_split_flag)
{
part_type_results_t *ps_data = &ps_child_data->ps_best_results[i4_result_id];
if(ps_child_data->u1_num_best_results <= i4_result_id)
{
continue;
}
if(ps_data->as_pu_results->pu.b1_intra_flag)
{
continue;
}
for(j = 0; j <= (ps_data->u1_part_type != PRT_2Nx2N); j++)
{
mv_t *ps_mv;
S08 i1_ref_idx;
pu_t *ps_pu = &ps_data->as_pu_results[j].pu;
if(u1_pred_dir !=
((ps_pu->b2_pred_mode == 2) ? u1_pred_dir : ps_pu->b2_pred_mode))
{
continue;
}
if(u1_pred_dir)
{
ps_mv = &ps_pu->mv.s_l1_mv;
i1_ref_idx = pi1_future_list[ps_pu->mv.i1_l1_ref_idx];
}
else
{
ps_mv = &ps_pu->mv.s_l0_mv;
i1_ref_idx = pi1_past_list[ps_pu->mv.i1_l0_ref_idx];
}
if(-1 == i1_ref_idx)
{
continue;
}
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvx = ps_mv->i2_mvx;
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvy = ps_mv->i2_mvy;
ps_merge_cand[i4_num_cands_added].i1_ref_idx = i1_ref_idx;
CLIP_MV_WITHIN_RANGE(
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvx,
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvy,
pps_range_prms[i1_ref_idx],
0,
0,
0);
for(k = 0; k < i4_num_cands_added; k++)
{
if((ps_merge_cand[k].s_mv.i2_mvx == ps_mv->i2_mvx) &&
(ps_merge_cand[k].s_mv.i2_mvy == ps_mv->i2_mvy) &&
(ps_merge_cand[k].i1_ref_idx == i1_ref_idx))
{
break;
}
}
if(k == i4_num_cands_added)
{
i4_num_cands_added++;
if(i4_max_cands_to_add <= i4_num_cands_added)
{
return i4_num_cands_added;
}
}
}
}
else
{
for(j = 0; j < 4; j++)
{
mv_t *ps_mv;
S08 i1_ref_idx;
part_type_results_t *ps_data = ps_grandchild_data[j].ps_best_results;
pu_t *ps_pu = &ps_data->as_pu_results[0].pu;
ASSERT(ps_data->u1_part_type == PRT_2Nx2N);
if(ps_grandchild_data[j].u1_num_best_results <= i4_result_id)
{
continue;
}
if(ps_data->as_pu_results->pu.b1_intra_flag)
{
continue;
}
if(u1_pred_dir !=
((ps_pu->b2_pred_mode == 2) ? u1_pred_dir : ps_pu->b2_pred_mode))
{
continue;
}
if(u1_pred_dir)
{
ps_mv = &ps_pu->mv.s_l1_mv;
i1_ref_idx = pi1_future_list[ps_pu->mv.i1_l1_ref_idx];
}
else
{
ps_mv = &ps_pu->mv.s_l0_mv;
i1_ref_idx = pi1_past_list[ps_pu->mv.i1_l0_ref_idx];
}
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvx = ps_mv->i2_mvx;
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvy = ps_mv->i2_mvy;
ps_merge_cand[i4_num_cands_added].i1_ref_idx = i1_ref_idx;
CLIP_MV_WITHIN_RANGE(
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvx,
ps_merge_cand[i4_num_cands_added].s_mv.i2_mvy,
pps_range_prms[i1_ref_idx],
0,
0,
0);
for(k = 0; k < i4_num_cands_added; k++)
{
if((ps_merge_cand[k].s_mv.i2_mvx == ps_mv->i2_mvx) &&
(ps_merge_cand[k].s_mv.i2_mvy == ps_mv->i2_mvy) &&
(ps_merge_cand[k].i1_ref_idx == i1_ref_idx))
{
break;
}
}
if(k == i4_num_cands_added)
{
i4_num_cands_added++;
if(i4_max_cands_to_add <= i4_num_cands_added)
{
return i4_num_cands_added;
}
}
}
}
}
i4_result_id++;
}
return i4_num_cands_added;
}
WORD32 hme_add_cands_for_merge_eval(
ctb_cluster_info_t *ps_cluster_info,
search_results_t **pps_child_data_array,
inter_cu_results_t *ps_8x8cu_results,
range_prms_t **pps_range_prms,
search_node_t *ps_merge_cand,
U08 *pu1_refid_to_pred_dir_list,
S08 *pi1_past_list,
S08 *pi1_future_list,
ME_QUALITY_PRESETS_T e_quality_preset,
BLK_SIZE_T e_blk_size,
U08 u1_pred_dir,
U08 u1_blk_id)
{
WORD32 i4_num_cands_added = 0;
if(ME_PRISTINE_QUALITY == e_quality_preset)
{
cluster_data_t *ps_cluster_primo;
WORD32 i4_num_clusters;
if(BLK_32x32 == e_blk_size)
{
ps_cluster_primo = ps_cluster_info->ps_32x32_blk[u1_blk_id].as_cluster_data;
i4_num_clusters = ps_cluster_info->ps_32x32_blk[u1_blk_id].num_clusters;
}
else
{
ps_cluster_primo = ps_cluster_info->ps_64x64_blk->as_cluster_data;
i4_num_clusters = ps_cluster_info->ps_64x64_blk->num_clusters;
}
i4_num_cands_added = hme_add_clustered_mvs_as_merge_cands(
ps_cluster_primo,
ps_merge_cand,
pps_range_prms,
pu1_refid_to_pred_dir_list,
i4_num_clusters,
u1_pred_dir);
}
i4_num_cands_added = hme_add_me_best_as_merge_cands(
pps_child_data_array,
ps_8x8cu_results,
ps_merge_cand,
pps_range_prms,
pu1_refid_to_pred_dir_list,
pi1_past_list,
pi1_future_list,
e_blk_size,
e_quality_preset,
i4_num_cands_added,
u1_pred_dir);
return i4_num_cands_added;
}
/**
********************************************************************************
* @fn void hme_pick_refine_merge_candts(hme_merge_prms_t *ps_merge_prms,
* S08 i1_ref_idx,
* S32 i4_best_part_type,
* S32 i4_is_vert)
*
* @brief Given a target partition orientation in the merged CU, and the
* partition type of most likely partition this fxn picks up
* candidates from the 4 constituent CUs and does refinement search
* to identify best results for the merge CU across active partitions
*
* @param[in,out] ps_merge_prms : Parameters sent from higher layers. Out of
* these params, the search result structure is also derived and
* updated during the search
*
* @param[in] i1_ref_idx : ID of the buffer within the search results to update.
* Will be 0 if all refidx collapsed to one buf, else it'll be 0/1
*
* @param[in] i4_best_part_type : partition type of potential partition in the
* merged CU, -1 if the merge process has not yet been able to
* determine this.
*
* @param[in] i4_is_vert : Whether target partition of merged CU is vertical
* orientation or horizontal orientation.
*
* @return Number of merge candidates
********************************************************************************
*/
WORD32 hme_pick_eval_merge_candts(
hme_merge_prms_t *ps_merge_prms,
hme_subpel_prms_t *ps_subpel_prms,
S32 i4_search_idx,
S32 i4_best_part_type,
S32 i4_is_vert,
wgt_pred_ctxt_t *ps_wt_inp_prms,
S32 i4_frm_qstep,
ihevce_cmn_opt_func_t *ps_cmn_utils_optimised_function_list,
ihevce_me_optimised_function_list_t *ps_me_optimised_function_list)
{
S32 x_off, y_off;
search_node_t *ps_search_node;
S32 ai4_valid_part_ids[TOT_NUM_PARTS + 1];
S32 i4_num_valid_parts;
pred_ctxt_t *ps_pred_ctxt;
search_node_t as_merge_unique_node[MAX_MERGE_CANDTS];
S32 num_unique_nodes_cu_merge = 0;
search_results_t *ps_search_results = ps_merge_prms->ps_results_merge;
CU_SIZE_T e_cu_size = ps_search_results->e_cu_size;
S32 i4_part_mask = ps_search_results->i4_part_mask;
search_results_t *aps_child_results[4];
layer_ctxt_t *ps_curr_layer = ps_merge_prms->ps_layer_ctxt;
S32 i4_ref_stride, i, j;
result_upd_prms_t s_result_prms;
BLK_SIZE_T e_blk_size = ge_cu_size_to_blk_size[e_cu_size];
S32 i4_offset;
/*************************************************************************/
/* Function pointer for SAD/SATD, array and prms structure to pass to */
/* This function */
/*************************************************************************/
PF_SAD_FXN_T pf_err_compute;
S32 ai4_sad_grid[9][17];
err_prms_t s_err_prms;
/*************************************************************************/
/* Allowed MV RANGE */
/*************************************************************************/
range_prms_t **pps_range_prms = ps_merge_prms->aps_mv_range;
PF_INTERP_FXN_T pf_qpel_interp;
PF_MV_COST_FXN pf_mv_cost_compute;
WORD32 pred_lx;
U08 *apu1_hpel_ref[4];
interp_prms_t s_interp_prms;
S32 i4_interp_buf_id;
S32 i4_ctb_x_off = ps_merge_prms->i4_ctb_x_off;
S32 i4_ctb_y_off = ps_merge_prms->i4_ctb_y_off;
/* Sanity checks */
ASSERT((e_blk_size == BLK_64x64) || (e_blk_size == BLK_32x32));
s_err_prms.ps_cmn_utils_optimised_function_list = ps_cmn_utils_optimised_function_list;
/* Initialize all the ptrs to child CUs for merge decision */
aps_child_results[0] = ps_merge_prms->ps_results_tl;
aps_child_results[1] = ps_merge_prms->ps_results_tr;
aps_child_results[2] = ps_merge_prms->ps_results_bl;
aps_child_results[3] = ps_merge_prms->ps_results_br;
num_unique_nodes_cu_merge = 0;
pf_mv_cost_compute = compute_mv_cost_implicit_high_speed;
if(ME_PRISTINE_QUALITY == ps_merge_prms->e_quality_preset)
{
num_unique_nodes_cu_merge = hme_add_cands_for_merge_eval(
ps_merge_prms->ps_cluster_info,
aps_child_results,
ps_merge_prms->ps_8x8_cu_results,
pps_range_prms,
as_merge_unique_node,
ps_search_results->pu1_is_past,
ps_merge_prms->pi1_past_list,
ps_merge_prms->pi1_future_list,
ps_merge_prms->e_quality_preset,
e_blk_size,
i4_search_idx,
(ps_merge_prms->ps_results_merge->u1_x_off >> 5) +
(ps_merge_prms->ps_results_merge->u1_y_off >> 4));
}
else
{
/*************************************************************************/
/* Populate the list of unique search nodes in the child CUs for merge */
/* evaluation */
/*************************************************************************/
for(i = 0; i < 4; i++)
{
search_node_t s_search_node;
PART_TYPE_T e_part_type;
PART_ID_T e_part_id;
WORD32 part_num;
search_results_t *ps_child = aps_child_results[i];
if(ps_child->ps_cu_results->u1_num_best_results)
{
if(!((ps_child->ps_cu_results->ps_best_results->as_pu_results->pu.b1_intra_flag) &&
(1 == ps_child->ps_cu_results->u1_num_best_results)))
{
e_part_type =
(PART_TYPE_T)ps_child->ps_cu_results->ps_best_results[0].u1_part_type;
ASSERT(num_unique_nodes_cu_merge < MAX_MERGE_CANDTS);
/* Insert mvs of NxN partitions. */
for(part_num = 0; part_num < gau1_num_parts_in_part_type[((S32)e_part_type)];
part_num++)
{
e_part_id = ge_part_type_to_part_id[e_part_type][part_num];
if(ps_child->aps_part_results[i4_search_idx][e_part_id]->i1_ref_idx != -1)
{
s_search_node = *ps_child->aps_part_results[i4_search_idx][e_part_id];
if(s_search_node.s_mv.i2_mvx != INTRA_MV)
{
CLIP_MV_WITHIN_RANGE(
s_search_node.s_mv.i2_mvx,
s_search_node.s_mv.i2_mvy,
pps_range_prms[s_search_node.i1_ref_idx],
0,
0,
0);
INSERT_NEW_NODE_NOMAP(
as_merge_unique_node,
num_unique_nodes_cu_merge,
s_search_node,
1);
}
}
}
}
}
else if(!((ps_merge_prms->ps_results_grandchild[(i << 2)]
.ps_cu_results->ps_best_results->as_pu_results->pu.b1_intra_flag) &&
(1 == ps_merge_prms->ps_results_grandchild[(i << 2)]
.ps_cu_results->u1_num_best_results)))
{
search_results_t *ps_results_root = &ps_merge_prms->ps_results_grandchild[(i << 2)];
for(j = 0; j < 4; j++)
{
e_part_type = (PART_TYPE_T)ps_results_root[j]
.ps_cu_results->ps_best_results[0]
.u1_part_type;
ASSERT(num_unique_nodes_cu_merge < MAX_MERGE_CANDTS);
/* Insert mvs of NxN partitions. */
for(part_num = 0; part_num < gau1_num_parts_in_part_type[((S32)e_part_type)];
part_num++)
{
e_part_id = ge_part_type_to_part_id[e_part_type][part_num];
if((ps_results_root[j]
.aps_part_results[i4_search_idx][e_part_id]
->i1_ref_idx != -1) &&
(!ps_child->ps_cu_results->ps_best_results->as_pu_results->pu
.b1_intra_flag))
{
s_search_node =
*ps_results_root[j].aps_part_results[i4_search_idx][e_part_id];
if(s_search_node.s_mv.i2_mvx != INTRA_MV)
{
CLIP_MV_WITHIN_RANGE(
s_search_node.s_mv.i2_mvx,
s_search_node.s_mv.i2_mvy,
pps_range_prms[s_search_node.i1_ref_idx],
0,
0,
0);
INSERT_NEW_NODE_NOMAP(
as_merge_unique_node,
num_unique_nodes_cu_merge,
s_search_node,
1);
}
}
}
}
}
}
}
if(0 == num_unique_nodes_cu_merge)
{
return 0;
}
/*************************************************************************/
/* Appropriate Err compute fxn, depends on SAD/SATD, blk size and remains*/
/* fixed through this subpel refinement for this partition. */
/* Note, we do not enable grid sads since one pt is evaluated per node */
/* Hence, part mask is also nearly dont care and we use 2Nx2N enabled. */
/*************************************************************************/
i4_part_mask = ps_search_results->i4_part_mask;
/* Need to add the corresponding SAD functions for EXTREME SPEED : Lokesh */
if(ps_subpel_prms->i4_use_satd)
{
if(BLK_32x32 == e_blk_size)
{
pf_err_compute = hme_evalsatd_pt_pu_32x32;
}
else
{
pf_err_compute = hme_evalsatd_pt_pu_64x64;
}
}
else
{
pf_err_compute = (PF_SAD_FXN_T)hme_evalsad_grid_pu_MxM;
}
i4_ref_stride = ps_curr_layer->i4_rec_stride;
x_off = ps_merge_prms->ps_results_tl->u1_x_off;
y_off = ps_merge_prms->ps_results_tl->u1_y_off;
i4_offset = x_off + i4_ctb_x_off + ((y_off + i4_ctb_y_off) * i4_ref_stride);
/*************************************************************************/
/* This array stores the ids of the partitions whose */
/* SADs are updated. Since the partitions whose SADs are updated may not */
/* be in contiguous order, we supply another level of indirection. */
/*************************************************************************/
i4_num_valid_parts = hme_create_valid_part_ids(i4_part_mask, ai4_valid_part_ids);
/* Initialize result params used for partition update */
s_result_prms.pf_mv_cost_compute = NULL;
s_result_prms.ps_search_results = ps_search_results;
s_result_prms.pi4_valid_part_ids = ai4_valid_part_ids;
s_result_prms.i1_ref_idx = i4_search_idx;
s_result_prms.i4_part_mask = i4_part_mask;
s_result_prms.pi4_sad_grid = &ai4_sad_grid[0][0];
s_result_prms.i4_grid_mask = 1;
/* One time Initialization of error params used for SAD/SATD compute */
s_err_prms.i4_inp_stride = ps_subpel_prms->i4_inp_stride;
s_err_prms.i4_ref_stride = i4_ref_stride;
s_err_prms.i4_part_mask = (ENABLE_2Nx2N);
s_err_prms.i4_grid_mask = 1;
s_err_prms.pi4_sad_grid = &ai4_sad_grid[0][0];
s_err_prms.i4_blk_wd = gau1_blk_size_to_wd[e_blk_size];
s_err_prms.i4_blk_ht = gau1_blk_size_to_ht[e_blk_size];
s_err_prms.i4_step = 1;
/*************************************************************************/
/* One time preparation of non changing interpolation params. */
/*************************************************************************/
s_interp_prms.i4_ref_stride = i4_ref_stride;
s_interp_prms.i4_blk_wd = gau1_blk_size_to_wd[e_blk_size];
s_interp_prms.i4_blk_ht = gau1_blk_size_to_ht[e_blk_size];
s_interp_prms.apu1_interp_out[0] = ps_subpel_prms->pu1_wkg_mem;
s_interp_prms.i4_out_stride = gau1_blk_size_to_wd[e_blk_size];
i4_interp_buf_id = 0;
pf_qpel_interp = ps_subpel_prms->pf_qpel_interp;
/***************************************************************************/
/* Compute SATD/SAD for all unique nodes of children CUs to get best merge */
/* results */
/***************************************************************************/
for(i = 0; i < num_unique_nodes_cu_merge; i++)
{
WORD8 i1_ref_idx;
ps_search_node = &as_merge_unique_node[i];
/*********************************************************************/
/* Compute the base pointer for input, interpolated buffers */
/* The base pointers point as follows: */
/* fx fy : 0, 0 :: fx, hy : 0, 0.5, hx, fy: 0.5, 0, hx, fy: 0.5, 0.5 */
/* To these, we need to add the offset of the current node */
/*********************************************************************/
i1_ref_idx = ps_search_node->i1_ref_idx;
apu1_hpel_ref[0] = ps_curr_layer->ppu1_list_rec_fxfy[i1_ref_idx] + i4_offset;
apu1_hpel_ref[1] = ps_curr_layer->ppu1_list_rec_hxfy[i1_ref_idx] + i4_offset;
apu1_hpel_ref[2] = ps_curr_layer->ppu1_list_rec_fxhy[i1_ref_idx] + i4_offset;
apu1_hpel_ref[3] = ps_curr_layer->ppu1_list_rec_hxhy[i1_ref_idx] + i4_offset;
s_interp_prms.ppu1_ref = &apu1_hpel_ref[0];
pf_qpel_interp(
&s_interp_prms,
ps_search_node->s_mv.i2_mvx,
ps_search_node->s_mv.i2_mvy,
i4_interp_buf_id);
pred_lx = i4_search_idx;
ps_pred_ctxt = &ps_search_results->as_pred_ctxt[pred_lx];
s_result_prms.u1_pred_lx = pred_lx;
s_result_prms.ps_search_node_base = ps_search_node;
s_err_prms.pu1_inp =
ps_wt_inp_prms->apu1_wt_inp[i1_ref_idx] + x_off + y_off * ps_subpel_prms->i4_inp_stride;
s_err_prms.pu1_ref = s_interp_prms.pu1_final_out;
s_err_prms.i4_ref_stride = s_interp_prms.i4_final_out_stride;
/* Carry out the SAD/SATD. This call also does the TU RECURSION.
Here the tu recursion logic is restricted with the size of the PU*/
pf_err_compute(&s_err_prms);
if(ps_subpel_prms->u1_is_cu_noisy &&
ps_merge_prms->ps_inter_ctb_prms->i4_alpha_stim_multiplier)
{
ps_me_optimised_function_list->pf_compute_stim_injected_distortion_for_all_parts(
s_err_prms.pu1_ref,
s_err_prms.i4_ref_stride,
ai4_valid_part_ids,
ps_merge_prms->ps_inter_ctb_prms->pu8_part_src_sigmaX,
ps_merge_prms->ps_inter_ctb_prms->pu8_part_src_sigmaXSquared,
s_err_prms.pi4_sad_grid,
ps_merge_prms->ps_inter_ctb_prms->i4_alpha_stim_multiplier,
ps_wt_inp_prms->a_inv_wpred_wt[i1_ref_idx],
ps_wt_inp_prms->ai4_shift_val[i1_ref_idx],
i4_num_valid_parts,
ps_wt_inp_prms->wpred_log_wdc,
(BLK_32x32 == e_blk_size) ? 32 : 64);
}
/* Update the mv's */
s_result_prms.i2_mv_x = ps_search_node->s_mv.i2_mvx;
s_result_prms.i2_mv_y = ps_search_node->s_mv.i2_mvy;
/* Update best results */
hme_update_results_pt_pu_best1_subpel_hs(&s_err_prms, &s_result_prms);
}
/************************************************************************/
/* Update mv cost and total cost for each valid partition in the CU */
/************************************************************************/
for(i = 0; i < TOT_NUM_PARTS; i++)
{
if(i4_part_mask & (1 << i))
{
WORD32 j;
WORD32 i4_mv_cost;
ps_search_node = ps_search_results->aps_part_results[i4_search_idx][i];
for(j = 0;
j < MIN(ps_search_results->u1_num_results_per_part, num_unique_nodes_cu_merge);
j++)
{
if(ps_search_node->i1_ref_idx != -1)
{
pred_lx = i4_search_idx;
ps_pred_ctxt = &ps_search_results->as_pred_ctxt[pred_lx];
/* Prediction context should now deal with qpel units */
HME_SET_MVPRED_RES(ps_pred_ctxt, MV_RES_QPEL);
ps_search_node->u1_subpel_done = 1;
ps_search_node->u1_is_avail = 1;
i4_mv_cost =
pf_mv_cost_compute(ps_search_node, ps_pred_ctxt, (PART_ID_T)i, MV_RES_QPEL);
ps_search_node->i4_tot_cost = i4_mv_cost + ps_search_node->i4_sad;
ps_search_node->i4_mv_cost = i4_mv_cost;
ps_search_node++;
}
}
}
}
return num_unique_nodes_cu_merge;
}
#define CU_MERGE_MAX_INTRA_PARTS 4
/**
********************************************************************************
* @fn hme_try_merge_high_speed
*
* @brief Attempts to merge 4 NxN candts to a 2Nx2N candt, either as a single
entity or with partititons for high speed preset
*
* @param[in,out] hme_merge_prms_t: Params for CU merge
*
* @return MERGE_RESULT_T type result of merge (CU_MERGED/CU_SPLIT)
********************************************************************************
*/
CU_MERGE_RESULT_T hme_try_merge_high_speed(
me_ctxt_t *ps_thrd_ctxt,
me_frm_ctxt_t *ps_ctxt,
ipe_l0_ctb_analyse_for_me_t *ps_cur_ipe_ctb,
hme_subpel_prms_t *ps_subpel_prms,
hme_merge_prms_t *ps_merge_prms,
inter_pu_results_t *ps_pu_results,
pu_result_t *ps_pu_result)
{
search_results_t *ps_results_tl, *ps_results_tr;
search_results_t *ps_results_bl, *ps_results_br;
S32 i;
S32 i4_search_idx;
S32 i4_cost_parent;
S32 intra_cu_size;
ULWORD64 au8_final_src_sigmaX[17], au8_final_src_sigmaXSquared[17];
search_results_t *ps_results_merge = ps_merge_prms->ps_results_merge;
wgt_pred_ctxt_t *ps_wt_inp_prms = &ps_ctxt->s_wt_pred;
S32 i4_part_mask = ENABLE_ALL_PARTS - ENABLE_NxN;
S32 is_vert = 0, i4_best_part_type = -1;
S32 i4_intra_parts = 0; /* Keeps track of intra percentage before merge */
S32 i4_cost_children = 0;
S32 i4_frm_qstep = ps_ctxt->frm_qstep;
S32 i4_num_merge_cands_evaluated = 0;
U08 u1_x_off = ps_results_merge->u1_x_off;
U08 u1_y_off = ps_results_merge->u1_y_off;
S32 i4_32x32_id = (u1_y_off >> 4) + (u1_x_off >> 5);
ihevce_cmn_opt_func_t *ps_cmn_utils_optimised_function_list =
ps_thrd_ctxt->ps_cmn_utils_optimised_function_list;
ihevce_me_optimised_function_list_t *ps_me_optimised_function_list =
((ihevce_me_optimised_function_list_t *)ps_thrd_ctxt->pv_me_optimised_function_list);
ps_results_tl = ps_merge_prms->ps_results_tl;
ps_results_tr = ps_merge_prms->ps_results_tr;
ps_results_bl = ps_merge_prms->ps_results_bl;
ps_results_br = ps_merge_prms->ps_results_br;
if(ps_merge_prms->e_quality_preset == ME_XTREME_SPEED)
{
i4_part_mask &= ~ENABLE_AMP;
}
if(ps_merge_prms->e_quality_preset == ME_XTREME_SPEED_25)
{
i4_part_mask &= ~ENABLE_AMP;
i4_part_mask &= ~ENABLE_SMP;
}
ps_merge_prms->i4_num_pred_dir_actual = 0;
/*************************************************************************/
/* The logic for High speed CU merge goes as follows: */
/* */
/* 1. Early exit with CU_SPLIT if sum of best partitions of children CUs */
/* exceed 7 */
/* 2. Early exit with CU_MERGE if mvs of best partitions of children CUs */
/* are identical */
/* 3. Find the all unique mvs of best partitions of children CUs and */
/* evaluate partial SATDs (all 17 partitions) for each unique mv. If */
/* best parent cost is lower than sum of the best children costs */
/* return CU_MERGE after seeding the best results else return CU_SPLIT*/
/* */
/*************************************************************************/
/* Count the number of best partitions in child CUs, early exit if > 7 */
if((ps_merge_prms->e_quality_preset != ME_PRISTINE_QUALITY) ||
(CU_32x32 == ps_results_merge->e_cu_size))
{
S32 num_parts_in_32x32 = 0;
WORD32 i4_part_type;
if(ps_results_tl->u1_split_flag)
{
num_parts_in_32x32 += 4;
#define COST_INTERCHANGE 0
i4_cost_children = ps_merge_prms->ps_8x8_cu_results[0].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[1].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[2].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[3].ps_best_results->i4_tot_cost;
}
else
{
i4_part_type = ps_results_tl->ps_cu_results->ps_best_results[0].u1_part_type;
num_parts_in_32x32 += gau1_num_parts_in_part_type[i4_part_type];
i4_cost_children = ps_results_tl->ps_cu_results->ps_best_results[0].i4_tot_cost;
}
if(ps_results_tr->u1_split_flag)
{
num_parts_in_32x32 += 4;
i4_cost_children += ps_merge_prms->ps_8x8_cu_results[4].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[5].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[6].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[7].ps_best_results->i4_tot_cost;
}
else
{
i4_part_type = ps_results_tr->ps_cu_results->ps_best_results[0].u1_part_type;
num_parts_in_32x32 += gau1_num_parts_in_part_type[i4_part_type];
i4_cost_children += ps_results_tr->ps_cu_results->ps_best_results[0].i4_tot_cost;
}
if(ps_results_bl->u1_split_flag)
{
num_parts_in_32x32 += 4;
i4_cost_children += ps_merge_prms->ps_8x8_cu_results[8].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[9].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[10].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[11].ps_best_results->i4_tot_cost;
}
else
{
i4_part_type = ps_results_bl->ps_cu_results->ps_best_results[0].u1_part_type;
num_parts_in_32x32 += gau1_num_parts_in_part_type[i4_part_type];
i4_cost_children += ps_results_bl->ps_cu_results->ps_best_results[0].i4_tot_cost;
}
if(ps_results_br->u1_split_flag)
{
num_parts_in_32x32 += 4;
i4_cost_children += ps_merge_prms->ps_8x8_cu_results[12].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[13].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[14].ps_best_results->i4_tot_cost +
ps_merge_prms->ps_8x8_cu_results[15].ps_best_results->i4_tot_cost;
}
else
{
i4_part_type = ps_results_br->ps_cu_results->ps_best_results[0].u1_part_type;
num_parts_in_32x32 += gau1_num_parts_in_part_type[i4_part_type];
i4_cost_children += ps_results_br->ps_cu_results->ps_best_results[0].i4_tot_cost;
}
if((num_parts_in_32x32 > 7) && (ps_merge_prms->e_quality_preset != ME_PRISTINE_QUALITY))
{
return CU_SPLIT;
}
if((num_parts_in_32x32 > MAX_NUM_CONSTITUENT_MVS_TO_ENABLE_32MERGE_IN_XS25) &&
(ps_merge_prms->e_quality_preset == ME_XTREME_SPEED_25))
{
return CU_SPLIT;
}
}
/* Accumulate intra percentage before merge for early CU_SPLIT decision */
/* Note : Each intra part represent a NxN unit of the children CUs */
/* This is essentially 1/16th of the CUsize under consideration for merge */
if(ME_PRISTINE_QUALITY == ps_merge_prms->e_quality_preset)
{
if(CU_64x64 == ps_results_merge->e_cu_size)
{
i4_intra_parts =
(!ps_merge_prms->ps_cluster_info->ps_cu_tree_root->u1_inter_eval_enable)
? 16
: ps_merge_prms->ps_cluster_info->ps_cu_tree_root->u1_intra_eval_enable;
}
else
{
switch((ps_results_merge->u1_x_off >> 5) + ((ps_results_merge->u1_y_off >> 4)))
{
case 0:
{
i4_intra_parts = (!ps_merge_prms->ps_cluster_info->ps_cu_tree_root->ps_child_node_tl
->u1_inter_eval_enable)
? 16
: (ps_merge_prms->ps_cluster_info->ps_cu_tree_root
->ps_child_node_tl->u1_intra_eval_enable);
break;
}
case 1:
{
i4_intra_parts = (!ps_merge_prms->ps_cluster_info->ps_cu_tree_root->ps_child_node_tr
->u1_inter_eval_enable)
? 16
: (ps_merge_prms->ps_cluster_info->ps_cu_tree_root
->ps_child_node_tr->u1_intra_eval_enable);
break;
}
case 2:
{
i4_intra_parts = (!ps_merge_prms->ps_cluster_info->ps_cu_tree_root->ps_child_node_bl
->u1_inter_eval_enable)
? 16
: (ps_merge_prms->ps_cluster_info->ps_cu_tree_root
->ps_child_node_bl->u1_intra_eval_enable);
break;
}
case 3:
{
i4_intra_parts = (!ps_merge_prms->ps_cluster_info->ps_cu_tree_root->ps_child_node_br
->u1_inter_eval_enable)
? 16
: (ps_merge_prms->ps_cluster_info->ps_cu_tree_root
->ps_child_node_br->u1_intra_eval_enable);
break;
}
}
}
}
else
{
for(i = 0; i < 4; i++)
{
search_results_t *ps_results =
(i == 0) ? ps_results_tl
: ((i == 1) ? ps_results_tr : ((i == 2) ? ps_results_bl : ps_results_br));
part_type_results_t *ps_best_res = &ps_results->ps_cu_results->ps_best_results[0];
if(ps_results->u1_split_flag)
{
U08 u1_x_off = ps_results->u1_x_off;
U08 u1_y_off = ps_results->u1_y_off;
U08 u1_8x8_zscan_id = gau1_ctb_raster_to_zscan[(u1_x_off >> 2) + (u1_y_off << 2)] >>
2;
/* Special case to handle 8x8 CUs when 16x16 is split */
ASSERT(ps_results->e_cu_size == CU_16x16);
ps_best_res = &ps_ctxt->as_cu8x8_results[u1_8x8_zscan_id].ps_best_results[0];
if(ps_best_res->as_pu_results[0].pu.b1_intra_flag)
i4_intra_parts += 1;
ps_best_res = &ps_ctxt->as_cu8x8_results[u1_8x8_zscan_id + 1].ps_best_results[0];
if(ps_best_res->as_pu_results[0].pu.b1_intra_flag)
i4_intra_parts += 1;
ps_best_res = &ps_ctxt->as_cu8x8_results[u1_8x8_zscan_id + 2].ps_best_results[0];
if(ps_best_res->as_pu_results[0].pu.b1_intra_flag)
i4_intra_parts += 1;
ps_best_res = &ps_ctxt->as_cu8x8_results[u1_8x8_zscan_id + 3].ps_best_results[0];
if(ps_best_res->as_pu_results[0].pu.b1_intra_flag)
i4_intra_parts += 1;
}
else if(ps_best_res[0].as_pu_results[0].pu.b1_intra_flag)
{
i4_intra_parts += 4;
}
}
}
/* Determine the max intra CU size indicated by IPE */
intra_cu_size = CU_64x64;
if(ps_cur_ipe_ctb->u1_split_flag)
{
intra_cu_size = CU_32x32;
if(ps_cur_ipe_ctb->as_intra32_analyse[i4_32x32_id].b1_split_flag)
{
intra_cu_size = CU_16x16;
}
}
if(((i4_intra_parts > CU_MERGE_MAX_INTRA_PARTS) &&
(intra_cu_size < ps_results_merge->e_cu_size) &&
(ME_PRISTINE_QUALITY != ps_merge_prms->e_quality_preset)) ||
(i4_intra_parts == 16))
{
S32 i4_merge_outcome;
i4_merge_outcome = (CU_32x32 == ps_results_merge->e_cu_size)
? (!ps_cur_ipe_ctb->as_intra32_analyse[i4_32x32_id].b1_split_flag &&
ps_cur_ipe_ctb->as_intra32_analyse[i4_32x32_id].b1_valid_cu)
: (!ps_cur_ipe_ctb->u1_split_flag);
i4_merge_outcome = i4_merge_outcome ||
(ME_PRISTINE_QUALITY == ps_merge_prms->e_quality_preset);
i4_merge_outcome = i4_merge_outcome &&
!(ps_subpel_prms->u1_is_cu_noisy && DISABLE_INTRA_WHEN_NOISY);
if(i4_merge_outcome)
{
inter_cu_results_t *ps_cu_results = ps_results_merge->ps_cu_results;
part_type_results_t *ps_best_result = ps_cu_results->ps_best_results;
pu_t *ps_pu = &ps_best_result->as_pu_results->pu;
ps_cu_results->u1_num_best_results = 1;
ps_cu_results->u1_cu_size = ps_results_merge->e_cu_size;
ps_cu_results->u1_x_off = u1_x_off;
ps_cu_results->u1_y_off = u1_y_off;
ps_best_result->u1_part_type = PRT_2Nx2N;
ps_best_result->ai4_tu_split_flag[0] = 0;
ps_best_result->ai4_tu_split_flag[1] = 0;
ps_best_result->ai4_tu_split_flag[2] = 0;
ps_best_result->ai4_tu_split_flag[3] = 0;
ps_best_result->i4_tot_cost =
(CU_64x64 == ps_results_merge->e_cu_size)
? ps_cur_ipe_ctb->i4_best64x64_intra_cost
: ps_cur_ipe_ctb->ai4_best32x32_intra_cost[i4_32x32_id];
ps_pu->b1_intra_flag = 1;
ps_pu->b4_pos_x = u1_x_off >> 2;
ps_pu->b4_pos_y = u1_y_off >> 2;
ps_pu->b4_wd = (1 << (ps_results_merge->e_cu_size + 1)) - 1;
ps_pu->b4_ht = ps_pu->b4_wd;
ps_pu->mv.i1_l0_ref_idx = -1;
ps_pu->mv.i1_l1_ref_idx = -1;
ps_pu->mv.s_l0_mv.i2_mvx = INTRA_MV;
ps_pu->mv.s_l0_mv.i2_mvy = INTRA_MV;
ps_pu->mv.s_l1_mv.i2_mvx = INTRA_MV;
ps_pu->mv.s_l1_mv.i2_mvy = INTRA_MV;
return CU_MERGED;
}
else
{
return CU_SPLIT;
}
}
if(i4_intra_parts)
{
i4_part_mask = ENABLE_2Nx2N;
}
ps_results_merge->u1_num_active_ref = (ps_ctxt->s_frm_prms.bidir_enabled) ? 2 : 1;
hme_reset_search_results(ps_results_merge, i4_part_mask, MV_RES_QPEL);
ps_results_merge->u1_num_active_ref = ps_merge_prms->i4_num_ref;
ps_merge_prms->i4_num_pred_dir_actual = 0;
if(ps_subpel_prms->u1_is_cu_noisy && ps_merge_prms->ps_inter_ctb_prms->i4_alpha_stim_multiplier)
{
S32 ai4_valid_part_ids[TOT_NUM_PARTS + 1];
S32 i4_num_valid_parts;
S32 i4_sigma_array_offset;
i4_num_valid_parts = hme_create_valid_part_ids(i4_part_mask, ai4_valid_part_ids);
/*********************************************************************************************************************************************/
/* i4_sigma_array_offset : takes care of pointing to the appropriate 4x4 block's sigmaX and sigmaX-squared value in a CTB out of 256 values */
/* Logic is x/4 + ((y/4) x 16) : every 4 pixel increase in x equals one 4x4 block increment, every 4 pixel increase in y equals 16 4x4 block */
/* increment as there will be 256 4x4 blocks in a CTB */
/*********************************************************************************************************************************************/
i4_sigma_array_offset = (ps_merge_prms->ps_results_merge->u1_x_off / 4) +
(ps_merge_prms->ps_results_merge->u1_y_off * 4);
for(i = 0; i < i4_num_valid_parts; i++)
{
S32 i4_part_id = ai4_valid_part_ids[i];
hme_compute_final_sigma_of_pu_from_base_blocks(
ps_ctxt->au4_4x4_src_sigmaX + i4_sigma_array_offset,
ps_ctxt->au4_4x4_src_sigmaXSquared + i4_sigma_array_offset,
au8_final_src_sigmaX,
au8_final_src_sigmaXSquared,
(CU_32x32 == ps_results_merge->e_cu_size) ? 32 : 64,
4,
i4_part_id,
16);
}
ps_merge_prms->ps_inter_ctb_prms->pu8_part_src_sigmaX = au8_final_src_sigmaX;
ps_merge_prms->ps_inter_ctb_prms->pu8_part_src_sigmaXSquared = au8_final_src_sigmaXSquared;
}
/*************************************************************************/
/* Loop through all ref idx and pick the merge candts and refine based */
/* on the active partitions. At this stage num ref will be 1 or 2 */
/*************************************************************************/
for(i4_search_idx = 0; i4_search_idx < ps_merge_prms->i4_num_ref; i4_search_idx++)
{
S32 i4_cands;
U08 u1_pred_dir = 0;
if((2 == ps_merge_prms->i4_num_ref) || (!ps_ctxt->s_frm_prms.bidir_enabled))
{
u1_pred_dir = i4_search_idx;
}
else if(ps_ctxt->s_frm_prms.u1_num_active_ref_l0 == 0)
{
u1_pred_dir = 1;
}
else if(ps_ctxt->s_frm_prms.u1_num_active_ref_l1 == 0)
{
u1_pred_dir = 0;
}
else
{
ASSERT(0);
}
/* call the function to pick and evaluate the merge candts, given */
/* a ref id and a part mask. */
i4_cands = hme_pick_eval_merge_candts(
ps_merge_prms,
ps_subpel_prms,
u1_pred_dir,
i4_best_part_type,
is_vert,
ps_wt_inp_prms,
i4_frm_qstep,
ps_cmn_utils_optimised_function_list,
ps_me_optimised_function_list);
if(i4_cands)
{
ps_merge_prms->au1_pred_dir_searched[ps_merge_prms->i4_num_pred_dir_actual] =
u1_pred_dir;
ps_merge_prms->i4_num_pred_dir_actual++;
}
i4_num_merge_cands_evaluated += i4_cands;
}
/* Call the decide_part_types function here */
/* Populate the new PU struct with the results post subpel refinement*/
if(i4_num_merge_cands_evaluated)
{
inter_cu_results_t *ps_cu_results = ps_results_merge->ps_cu_results;
hme_reset_wkg_mem(&ps_ctxt->s_buf_mgr);
ps_merge_prms->ps_inter_ctb_prms->i4_ctb_x_off = ps_merge_prms->i4_ctb_x_off;
ps_merge_prms->ps_inter_ctb_prms->i4_ctb_y_off = ps_merge_prms->i4_ctb_y_off;
hme_populate_pus(
ps_thrd_ctxt,
ps_ctxt,
ps_subpel_prms,
ps_results_merge,
ps_cu_results,
ps_pu_results,
ps_pu_result,
ps_merge_prms->ps_inter_ctb_prms,
&ps_ctxt->s_wt_pred,
ps_merge_prms->ps_layer_ctxt,
ps_merge_prms->au1_pred_dir_searched,
ps_merge_prms->i4_num_pred_dir_actual);
ps_cu_results->i4_inp_offset = (ps_cu_results->u1_x_off) + (ps_cu_results->u1_y_off * 64);
hme_decide_part_types(
ps_cu_results,
ps_pu_results,
ps_merge_prms->ps_inter_ctb_prms,
ps_ctxt,
ps_cmn_utils_optimised_function_list,
ps_me_optimised_function_list
);
/*****************************************************************/
/* INSERT INTRA RESULTS AT 32x32/64x64 LEVEL. */
/*****************************************************************/
#if DISABLE_INTRA_IN_BPICS
if(1 != ((ME_XTREME_SPEED_25 == ps_merge_prms->e_quality_preset) &&
(ps_ctxt->s_frm_prms.i4_temporal_layer_id > TEMPORAL_LAYER_DISABLE)))
#endif
{
if(!(DISABLE_INTRA_WHEN_NOISY && ps_merge_prms->ps_inter_ctb_prms->u1_is_cu_noisy))
{
hme_insert_intra_nodes_post_bipred(
ps_cu_results, ps_cur_ipe_ctb, ps_ctxt->frm_qstep);
}
}
}
else
{
return CU_SPLIT;
}
/* We check the best result of ref idx 0 and compare for parent vs child */
if((ps_merge_prms->e_quality_preset != ME_PRISTINE_QUALITY) ||
(CU_32x32 == ps_results_merge->e_cu_size))
{
i4_cost_parent = ps_results_merge->ps_cu_results->ps_best_results[0].i4_tot_cost;
/*********************************************************************/
/* Add the cost of signaling the CU tree bits. */
/* Assuming parent is not split, then we signal 1 bit for this parent*/
/* CU. If split, then 1 bit for parent CU + 4 bits for each child CU */
/* So, 4*lambda is extra for children cost. :Lokesh */
/*********************************************************************/
{
pred_ctxt_t *ps_pred_ctxt = &ps_results_merge->as_pred_ctxt[0];
i4_cost_children += ((4 * ps_pred_ctxt->lambda) >> (ps_pred_ctxt->lambda_q_shift));
}
if(i4_cost_parent < i4_cost_children)
{
return CU_MERGED;
}
return CU_SPLIT;
}
else
{
return CU_MERGED;
}
}
#define COPY_SEARCH_RESULT(ps_mv, pi1_ref_idx, ps_search_node, shift) \
{ \
(ps_mv)->i2_mv_x = (ps_search_node)->s_mv.i2_mvx >> (shift); \
(ps_mv)->i2_mv_y = (ps_search_node)->s_mv.i2_mvy >> (shift); \
*(pi1_ref_idx) = (ps_search_node)->i1_ref_idx; \
}
/**
********************************************************************************
* @fn hme_update_mv_bank_noencode(search_results_t *ps_search_results,
* layer_mv_t *ps_layer_mv,
* S32 i4_search_blk_x,
* S32 i4_search_blk_y,
* mvbank_update_prms_t *ps_prms)
*
* @brief Updates the mv bank in case there is no further encodign to be done
*
* @param[in] ps_search_results: contains results for the block just searched
*
* @param[in,out] ps_layer_mv : Has pointer to mv bank amongst other things
*
* @param[in] i4_search_blk_x : col num of blk being searched
*
* @param[in] i4_search_blk_y : row num of blk being searched
*
* @param[in] ps_prms : contains certain parameters which govern how updatedone
*
* @return None
********************************************************************************
*/
void hme_update_mv_bank_noencode(
search_results_t *ps_search_results,
layer_mv_t *ps_layer_mv,
S32 i4_search_blk_x,
S32 i4_search_blk_y,
mvbank_update_prms_t *ps_prms)
{
hme_mv_t *ps_mv;
hme_mv_t *ps_mv1, *ps_mv2, *ps_mv3, *ps_mv4;
S08 *pi1_ref_idx, *pi1_ref_idx1, *pi1_ref_idx2, *pi1_ref_idx3, *pi1_ref_idx4;
S32 i4_blk_x, i4_blk_y, i4_offset;
S32 i4_j, i4_ref_id;
search_node_t *ps_search_node;
search_node_t *ps_search_node_8x8, *ps_search_node_4x4_1;
search_node_t *ps_search_node_4x4_2, *ps_search_node_4x4_3;
search_node_t *ps_search_node_4x4_4;
i4_blk_x = i4_search_blk_x << ps_prms->i4_shift;
i4_blk_y = i4_search_blk_y << ps_prms->i4_shift;
i4_offset = i4_blk_x + i4_blk_y * ps_layer_mv->i4_num_blks_per_row;
i4_offset *= ps_layer_mv->i4_num_mvs_per_blk;
/* Identify the correct offset in the mvbank and the reference id buf */
ps_mv = ps_layer_mv->ps_mv + i4_offset;
pi1_ref_idx = ps_layer_mv->pi1_ref_idx + i4_offset;
/*************************************************************************/
/* Supposing we store the mvs in the same blk size as we searched (e.g. */
/* we searched 8x8 blks and store results for 8x8 blks), then we can */
/* do a straightforward single update of results. This will have a 1-1 */
/* correspondence. */
/*************************************************************************/
if(ps_layer_mv->e_blk_size == ps_prms->e_search_blk_size)
{
for(i4_ref_id = 0; i4_ref_id < (S32)ps_prms->i4_num_ref; i4_ref_id++)
{
ps_search_node = ps_search_results->aps_part_results[i4_ref_id][PART_ID_2Nx2N];
for(i4_j = 0; i4_j < ps_layer_mv->i4_num_mvs_per_ref; i4_j++)
{
COPY_SEARCH_RESULT(ps_mv, pi1_ref_idx, ps_search_node, 0);
ps_mv++;
pi1_ref_idx++;
ps_search_node++;
}
}
return;
}
/*************************************************************************/
/* Case where search blk size is 8x8, but we update 4x4 results. In this */
/* case, we need to have NxN partitions enabled in search. */
/* Further, we update on a 1-1 basis the 4x4 blk mvs from the respective */
/* NxN partition. We also update the 8x8 result into each of the 4x4 bank*/
/*************************************************************************/
ASSERT(ps_layer_mv->e_blk_size == BLK_4x4);
ASSERT(ps_prms->e_search_blk_size == BLK_8x8);
ASSERT((ps_search_results->i4_part_mask & (ENABLE_NxN)) == (ENABLE_NxN));
/*************************************************************************/
/* For every 4x4 blk we store corresponding 4x4 results and 1 8x8 result */
/* hence the below check. */
/*************************************************************************/
ASSERT(ps_layer_mv->i4_num_mvs_per_ref <= ps_search_results->u1_num_results_per_part + 1);
ps_mv1 = ps_mv;
ps_mv2 = ps_mv1 + ps_layer_mv->i4_num_mvs_per_blk;
ps_mv3 = ps_mv1 + (ps_layer_mv->i4_num_mvs_per_row);
ps_mv4 = ps_mv3 + (ps_layer_mv->i4_num_mvs_per_blk);
pi1_ref_idx1 = pi1_ref_idx;
pi1_ref_idx2 = pi1_ref_idx1 + ps_layer_mv->i4_num_mvs_per_blk;
pi1_ref_idx3 = pi1_ref_idx1 + (ps_layer_mv->i4_num_mvs_per_row);
pi1_ref_idx4 = pi1_ref_idx3 + (ps_layer_mv->i4_num_mvs_per_blk);
for(i4_ref_id = 0; i4_ref_id < (S32)ps_search_results->u1_num_active_ref; i4_ref_id++)
{
ps_search_node_8x8 = ps_search_results->aps_part_results[i4_ref_id][PART_ID_2Nx2N];
ps_search_node_4x4_1 = ps_search_results->aps_part_results[i4_ref_id][PART_ID_NxN_TL];
ps_search_node_4x4_2 = ps_search_results->aps_part_results[i4_ref_id][PART_ID_NxN_TR];
ps_search_node_4x4_3 = ps_search_results->aps_part_results[i4_ref_id][PART_ID_NxN_BL];
ps_search_node_4x4_4 = ps_search_results->aps_part_results[i4_ref_id][PART_ID_NxN_BR];
COPY_SEARCH_RESULT(ps_mv1, pi1_ref_idx1, ps_search_node_4x4_1, 0);
ps_mv1++;
pi1_ref_idx1++;
ps_search_node_4x4_1++;
COPY_SEARCH_RESULT(ps_mv2, pi1_ref_idx2, ps_search_node_4x4_2, 0);
ps_mv2++;
pi1_ref_idx2++;
ps_search_node_4x4_2++;
COPY_SEARCH_RESULT(ps_mv3, pi1_ref_idx3, ps_search_node_4x4_3, 0);
ps_mv3++;
pi1_ref_idx3++;
ps_search_node_4x4_3++;
COPY_SEARCH_RESULT(ps_mv4, pi1_ref_idx4, ps_search_node_4x4_4, 0);
ps_mv4++;
pi1_ref_idx4++;
ps_search_node_4x4_4++;
if(ps_layer_mv->i4_num_mvs_per_ref > 1)
{
COPY_SEARCH_RESULT(ps_mv1, pi1_ref_idx1, ps_search_node_8x8, 0);
ps_mv1++;
pi1_ref_idx1++;
COPY_SEARCH_RESULT(ps_mv2, pi1_ref_idx2, ps_search_node_8x8, 0);
ps_mv2++;
pi1_ref_idx2++;
COPY_SEARCH_RESULT(ps_mv3, pi1_ref_idx3, ps_search_node_8x8, 0);
ps_mv3++;
pi1_ref_idx3++;
COPY_SEARCH_RESULT(ps_mv4, pi1_ref_idx4, ps_search_node_8x8, 0);
ps_mv4++;
pi1_ref_idx4++;
}
for(i4_j = 2; i4_j < ps_layer_mv->i4_num_mvs_per_ref; i4_j++)
{
COPY_SEARCH_RESULT(ps_mv1, pi1_ref_idx1, ps_search_node_4x4_1, 0);
ps_mv1++;
pi1_ref_idx1++;
ps_search_node_4x4_1++;
COPY_SEARCH_RESULT(ps_mv2, pi1_ref_idx2, ps_search_node_4x4_2, 0);
ps_mv2++;
pi1_ref_idx2++;
ps_search_node_4x4_2++;
COPY_SEARCH_RESULT(ps_mv3, pi1_ref_idx3, ps_search_node_4x4_3, 0);
ps_mv3++;
pi1_ref_idx3++;
ps_search_node_4x4_3++;
COPY_SEARCH_RESULT(ps_mv4, pi1_ref_idx4, ps_search_node_4x4_4, 0);
ps_mv4++;
pi1_ref_idx4++;
ps_search_node_4x4_4++;
}
}
}
void hme_update_mv_bank_encode(
search_results_t *ps_search_results,
layer_mv_t *ps_layer_mv,
S32 i4_search_blk_x,
S32 i4_search_blk_y,
mvbank_update_prms_t *ps_prms,
U08 *pu1_pred_dir_searched,
S32 i4_num_act_ref_l0)
{
hme_mv_t *ps_mv;
hme_mv_t *ps_mv1, *ps_mv2, *ps_mv3, *ps_mv4;
S08 *pi1_ref_idx, *pi1_ref_idx1, *pi1_ref_idx2, *pi1_ref_idx3, *pi1_ref_idx4;
S32 i4_blk_x, i4_blk_y, i4_offset;
S32 j, i, num_parts;
search_node_t *ps_search_node_tl, *ps_search_node_tr;
search_node_t *ps_search_node_bl, *ps_search_node_br;
search_node_t s_zero_mv;
WORD32 i4_part_type = ps_search_results->ps_cu_results->ps_best_results[0].u1_part_type;
i4_blk_x = i4_search_blk_x << ps_prms->i4_shift;
i4_blk_y = i4_search_blk_y << ps_prms->i4_shift;
i4_offset = i4_blk_x + i4_blk_y * ps_layer_mv->i4_num_blks_per_row;
i4_offset *= ps_layer_mv->i4_num_mvs_per_blk;
/* Identify the correct offset in the mvbank and the reference id buf */
ps_mv = ps_layer_mv->ps_mv + i4_offset;
pi1_ref_idx = ps_layer_mv->pi1_ref_idx + i4_offset;
ASSERT(ps_layer_mv->e_blk_size == BLK_8x8);
ASSERT(ps_prms->e_search_blk_size == BLK_16x16);
/*************************************************************************/
/* For every 4x4 blk we store corresponding 4x4 results and 1 8x8 result */
/* hence the below check. */
/*************************************************************************/
ASSERT(ps_layer_mv->i4_num_mvs_per_ref <= ps_search_results->u1_num_best_results);
ps_mv1 = ps_mv;
ps_mv2 = ps_mv1 + ps_layer_mv->i4_num_mvs_per_blk;
ps_mv3 = ps_mv1 + (ps_layer_mv->i4_num_mvs_per_row);
ps_mv4 = ps_mv3 + (ps_layer_mv->i4_num_mvs_per_blk);
pi1_ref_idx1 = pi1_ref_idx;
pi1_ref_idx2 = pi1_ref_idx1 + ps_layer_mv->i4_num_mvs_per_blk;
pi1_ref_idx3 = pi1_ref_idx1 + (ps_layer_mv->i4_num_mvs_per_row);
pi1_ref_idx4 = pi1_ref_idx3 + (ps_layer_mv->i4_num_mvs_per_blk);
/* Initialize zero mv: default mv used for intra mvs */
s_zero_mv.s_mv.i2_mvx = 0;
s_zero_mv.s_mv.i2_mvy = 0;
s_zero_mv.i1_ref_idx = 0;
if((ps_search_results->e_cu_size == CU_16x16) && (ps_search_results->u1_split_flag) &&
(ps_search_results->i4_part_mask & ENABLE_NxN))
{
i4_part_type = PRT_NxN;
}
for(i = 0; i < ps_prms->i4_num_ref; i++)
{
for(j = 0; j < ps_layer_mv->i4_num_mvs_per_ref; j++)
{
WORD32 i4_part_id = ge_part_type_to_part_id[i4_part_type][0];
num_parts = gau1_num_parts_in_part_type[i4_part_type];
ps_search_node_tl =
ps_search_results->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id];
if(num_parts == 1)
{
ps_search_node_tr = ps_search_node_tl;
ps_search_node_bl = ps_search_node_tl;
ps_search_node_br = ps_search_node_tl;
}
else if(num_parts == 2)
{
/* For vertically oriented partitions, tl, bl pt to same result */
/* For horizontally oriented partition, tl, tr pt to same result */
/* This means for AMP, 2 of the 8x8 blks in mv bank have ambiguous */
/* result, e.g. for 4x16L. Here left 2 8x8 have the 4x16L partition */
/* and right 2 8x8 have 12x16R partition */
if(gau1_is_vert_part[i4_part_type])
{
ps_search_node_tr =
ps_search_results
->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 1];
ps_search_node_bl = ps_search_node_tl;
}
else
{
ps_search_node_tr = ps_search_node_tl;
ps_search_node_bl =
ps_search_results
->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 1];
}
ps_search_node_br =
ps_search_results->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 1];
}
else
{
/* 4 unique results */
ps_search_node_tr =
ps_search_results->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 1];
ps_search_node_bl =
ps_search_results->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 2];
ps_search_node_br =
ps_search_results->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 3];
}
if(ps_search_node_tl->s_mv.i2_mvx == INTRA_MV)
ps_search_node_tl++;
if(ps_search_node_tr->s_mv.i2_mvx == INTRA_MV)
ps_search_node_tr++;
if(ps_search_node_bl->s_mv.i2_mvx == INTRA_MV)
ps_search_node_bl++;
if(ps_search_node_br->s_mv.i2_mvx == INTRA_MV)
ps_search_node_br++;
COPY_SEARCH_RESULT(ps_mv1, pi1_ref_idx1, ps_search_node_tl, 0);
ps_mv1++;
pi1_ref_idx1++;
COPY_SEARCH_RESULT(ps_mv2, pi1_ref_idx2, ps_search_node_tr, 0);
ps_mv2++;
pi1_ref_idx2++;
COPY_SEARCH_RESULT(ps_mv3, pi1_ref_idx3, ps_search_node_bl, 0);
ps_mv3++;
pi1_ref_idx3++;
COPY_SEARCH_RESULT(ps_mv4, pi1_ref_idx4, ps_search_node_br, 0);
ps_mv4++;
pi1_ref_idx4++;
if(ps_prms->i4_num_results_to_store > 1)
{
ps_search_node_tl =
&ps_search_results->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id][1];
if(num_parts == 1)
{
ps_search_node_tr = ps_search_node_tl;
ps_search_node_bl = ps_search_node_tl;
ps_search_node_br = ps_search_node_tl;
}
else if(num_parts == 2)
{
/* For vertically oriented partitions, tl, bl pt to same result */
/* For horizontally oriented partition, tl, tr pt to same result */
/* This means for AMP, 2 of the 8x8 blks in mv bank have ambiguous */
/* result, e.g. for 4x16L. Here left 2 8x8 have the 4x16L partition */
/* and right 2 8x8 have 12x16R partition */
if(gau1_is_vert_part[i4_part_type])
{
ps_search_node_tr =
&ps_search_results
->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 1][1];
ps_search_node_bl = ps_search_node_tl;
}
else
{
ps_search_node_tr = ps_search_node_tl;
ps_search_node_bl =
&ps_search_results
->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 1][1];
}
ps_search_node_br =
&ps_search_results
->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 1][1];
}
else
{
/* 4 unique results */
ps_search_node_tr =
&ps_search_results
->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 1][1];
ps_search_node_bl =
&ps_search_results
->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 2][1];
ps_search_node_br =
&ps_search_results
->aps_part_results[pu1_pred_dir_searched[i]][i4_part_id + 3][1];
}
if(ps_search_node_tl->s_mv.i2_mvx == INTRA_MV)
ps_search_node_tl++;
if(ps_search_node_tr->s_mv.i2_mvx == INTRA_MV)
ps_search_node_tr++;
if(ps_search_node_bl->s_mv.i2_mvx == INTRA_MV)
ps_search_node_bl++;
if(ps_search_node_br->s_mv.i2_mvx == INTRA_MV)
ps_search_node_br++;
COPY_SEARCH_RESULT(ps_mv1, pi1_ref_idx1, ps_search_node_tl, 0);
ps_mv1++;
pi1_ref_idx1++;
COPY_SEARCH_RESULT(ps_mv2, pi1_ref_idx2, ps_search_node_tr, 0);
ps_mv2++;
pi1_ref_idx2++;
COPY_SEARCH_RESULT(ps_mv3, pi1_ref_idx3, ps_search_node_bl, 0);
ps_mv3++;
pi1_ref_idx3++;
COPY_SEARCH_RESULT(ps_mv4, pi1_ref_idx4, ps_search_node_br, 0);
ps_mv4++;
pi1_ref_idx4++;
}
}
}
}
/**
********************************************************************************
* @fn hme_update_mv_bank_noencode(search_results_t *ps_search_results,
* layer_mv_t *ps_layer_mv,
* S32 i4_search_blk_x,
* S32 i4_search_blk_y,
* mvbank_update_prms_t *ps_prms)
*
* @brief Updates the mv bank in case there is no further encodign to be done
*
* @param[in] ps_search_results: contains results for the block just searched
*
* @param[in,out] ps_layer_mv : Has pointer to mv bank amongst other things
*
* @param[in] i4_search_blk_x : col num of blk being searched
*
* @param[in] i4_search_blk_y : row num of blk being searched
*
* @param[in] ps_prms : contains certain parameters which govern how updatedone
*
* @return None
********************************************************************************
*/
void hme_update_mv_bank_in_l1_me(
search_results_t *ps_search_results,
layer_mv_t *ps_layer_mv,
S32 i4_search_blk_x,
S32 i4_search_blk_y,
mvbank_update_prms_t *ps_prms)
{
hme_mv_t *ps_mv;
hme_mv_t *ps_mv1, *ps_mv2, *ps_mv3, *ps_mv4;
S08 *pi1_ref_idx, *pi1_ref_idx1, *pi1_ref_idx2, *pi1_ref_idx3, *pi1_ref_idx4;
S32 i4_blk_x, i4_blk_y, i4_offset;
S32 i4_j, i4_ref_id;
search_node_t *ps_search_node;
search_node_t *ps_search_node_8x8, *ps_search_node_4x4;
i4_blk_x = i4_search_blk_x << ps_prms->i4_shift;
i4_blk_y = i4_search_blk_y << ps_prms->i4_shift;
i4_offset = i4_blk_x + i4_blk_y * ps_layer_mv->i4_num_blks_per_row;
i4_offset *= ps_layer_mv->i4_num_mvs_per_blk;
/* Identify the correct offset in the mvbank and the reference id buf */
ps_mv = ps_layer_mv->ps_mv + i4_offset;
pi1_ref_idx = ps_layer_mv->pi1_ref_idx + i4_offset;
/*************************************************************************/
/* Supposing we store the mvs in the same blk size as we searched (e.g. */
/* we searched 8x8 blks and store results for 8x8 blks), then we can */
/* do a straightforward single update of results. This will have a 1-1 */
/* correspondence. */
/*************************************************************************/
if(ps_layer_mv->e_blk_size == ps_prms->e_search_blk_size)
{
search_node_t *aps_result_nodes_sorted[2][MAX_NUM_REF * 2];
hme_mv_t *ps_mv_l0_root = ps_mv;
hme_mv_t *ps_mv_l1_root =
ps_mv + (ps_prms->i4_num_active_ref_l0 * ps_layer_mv->i4_num_mvs_per_ref);
U32 u4_num_l0_results_updated = 0;
U32 u4_num_l1_results_updated = 0;
S08 *pi1_ref_idx_l0_root = pi1_ref_idx;
S08 *pi1_ref_idx_l1_root =
pi1_ref_idx_l0_root + (ps_prms->i4_num_active_ref_l0 * ps_layer_mv->i4_num_mvs_per_ref);
for(i4_ref_id = 0; i4_ref_id < (S32)ps_prms->i4_num_ref; i4_ref_id++)
{
U32 *pu4_num_results_updated;
search_node_t **pps_result_nodes;
U08 u1_pred_dir_of_cur_ref = !ps_search_results->pu1_is_past[i4_ref_id];
if(u1_pred_dir_of_cur_ref)
{
pu4_num_results_updated = &u4_num_l1_results_updated;
pps_result_nodes = &aps_result_nodes_sorted[1][0];
}
else
{
pu4_num_results_updated = &u4_num_l0_results_updated;
pps_result_nodes = &aps_result_nodes_sorted[0][0];
}
ps_search_node = ps_search_results->aps_part_results[i4_ref_id][PART_ID_2Nx2N];
for(i4_j = 0; i4_j < ps_layer_mv->i4_num_mvs_per_ref; i4_j++)
{
hme_add_new_node_to_a_sorted_array(
&ps_search_node[i4_j], pps_result_nodes, NULL, *pu4_num_results_updated, 0);
ASSERT(ps_search_node[i4_j].i1_ref_idx == i4_ref_id);
(*pu4_num_results_updated)++;
}
}
for(i4_j = 0; i4_j < (S32)u4_num_l0_results_updated; i4_j++)
{
COPY_SEARCH_RESULT(
&ps_mv_l0_root[i4_j],
&pi1_ref_idx_l0_root[i4_j],
aps_result_nodes_sorted[0][i4_j],
0);
}
for(i4_j = 0; i4_j < (S32)u4_num_l1_results_updated; i4_j++)
{
COPY_SEARCH_RESULT(
&ps_mv_l1_root[i4_j],
&pi1_ref_idx_l1_root[i4_j],
aps_result_nodes_sorted[1][i4_j],
0);
}
return;
}
/*************************************************************************/
/* Case where search blk size is 8x8, but we update 4x4 results. In this */
/* case, we need to have NxN partitions enabled in search. */
/* Further, we update on a 1-1 basis the 4x4 blk mvs from the respective */
/* NxN partition. We also update the 8x8 result into each of the 4x4 bank*/
/*************************************************************************/
ASSERT(ps_layer_mv->e_blk_size == BLK_4x4);
ASSERT(ps_prms->e_search_blk_size == BLK_8x8);
ASSERT((ps_search_results->i4_part_mask & (ENABLE_NxN)) == (ENABLE_NxN));
/*************************************************************************/
/* For every 4x4 blk we store corresponding 4x4 results and 1 8x8 result */
/* hence the below check. */
/*************************************************************************/
ASSERT(ps_layer_mv->i4_num_mvs_per_ref <= ps_search_results->u1_num_results_per_part + 1);
ps_mv1 = ps_mv;
ps_mv2 = ps_mv1 + ps_layer_mv->i4_num_mvs_per_blk;
ps_mv3 = ps_mv1 + (ps_layer_mv->i4_num_mvs_per_row);
ps_mv4 = ps_mv3 + (ps_layer_mv->i4_num_mvs_per_blk);
pi1_ref_idx1 = pi1_ref_idx;
pi1_ref_idx2 = pi1_ref_idx1 + ps_layer_mv->i4_num_mvs_per_blk;
pi1_ref_idx3 = pi1_ref_idx1 + (ps_layer_mv->i4_num_mvs_per_row);
pi1_ref_idx4 = pi1_ref_idx3 + (ps_layer_mv->i4_num_mvs_per_blk);
{
search_node_t *aps_result_nodes_sorted[2][MAX_NUM_REF * 4];
U08 au1_cost_shifts_for_sorted_node[2][MAX_NUM_REF * 4];
S32 i;
hme_mv_t *ps_mv1_l0_root = ps_mv1;
hme_mv_t *ps_mv1_l1_root =
ps_mv1 + (ps_prms->i4_num_active_ref_l0 * ps_layer_mv->i4_num_mvs_per_ref);
hme_mv_t *ps_mv2_l0_root = ps_mv2;
hme_mv_t *ps_mv2_l1_root =
ps_mv2 + (ps_prms->i4_num_active_ref_l0 * ps_layer_mv->i4_num_mvs_per_ref);
hme_mv_t *ps_mv3_l0_root = ps_mv3;
hme_mv_t *ps_mv3_l1_root =
ps_mv3 + (ps_prms->i4_num_active_ref_l0 * ps_layer_mv->i4_num_mvs_per_ref);
hme_mv_t *ps_mv4_l0_root = ps_mv4;
hme_mv_t *ps_mv4_l1_root =
ps_mv4 + (ps_prms->i4_num_active_ref_l0 * ps_layer_mv->i4_num_mvs_per_ref);
U32 u4_num_l0_results_updated = 0;
U32 u4_num_l1_results_updated = 0;
S08 *pi1_ref_idx1_l0_root = pi1_ref_idx1;
S08 *pi1_ref_idx1_l1_root = pi1_ref_idx1_l0_root + (ps_prms->i4_num_active_ref_l0 *
ps_layer_mv->i4_num_mvs_per_ref);
S08 *pi1_ref_idx2_l0_root = pi1_ref_idx2;
S08 *pi1_ref_idx2_l1_root = pi1_ref_idx2_l0_root + (ps_prms->i4_num_active_ref_l0 *
ps_layer_mv->i4_num_mvs_per_ref);
S08 *pi1_ref_idx3_l0_root = pi1_ref_idx3;
S08 *pi1_ref_idx3_l1_root = pi1_ref_idx3_l0_root + (ps_prms->i4_num_active_ref_l0 *
ps_layer_mv->i4_num_mvs_per_ref);
S08 *pi1_ref_idx4_l0_root = pi1_ref_idx4;
S08 *pi1_ref_idx4_l1_root = pi1_ref_idx4_l0_root + (ps_prms->i4_num_active_ref_l0 *
ps_layer_mv->i4_num_mvs_per_ref);
for(i = 0; i < 4; i++)
{
hme_mv_t *ps_mv_l0_root;
hme_mv_t *ps_mv_l1_root;
S08 *pi1_ref_idx_l0_root;
S08 *pi1_ref_idx_l1_root;
for(i4_ref_id = 0; i4_ref_id < ps_search_results->u1_num_active_ref; i4_ref_id++)
{
U32 *pu4_num_results_updated;
search_node_t **pps_result_nodes;
U08 *pu1_cost_shifts_for_sorted_node;
U08 u1_pred_dir_of_cur_ref = !ps_search_results->pu1_is_past[i4_ref_id];
if(u1_pred_dir_of_cur_ref)
{
pu4_num_results_updated = &u4_num_l1_results_updated;
pps_result_nodes = &aps_result_nodes_sorted[1][0];
pu1_cost_shifts_for_sorted_node = &au1_cost_shifts_for_sorted_node[1][0];
}
else
{
pu4_num_results_updated = &u4_num_l0_results_updated;
pps_result_nodes = &aps_result_nodes_sorted[0][0];
pu1_cost_shifts_for_sorted_node = &au1_cost_shifts_for_sorted_node[1][0];
}
ps_search_node_8x8 = ps_search_results->aps_part_results[i4_ref_id][PART_ID_2Nx2N];
ps_search_node_4x4 =
ps_search_results->aps_part_results[i4_ref_id][PART_ID_NxN_TL + i];
for(i4_j = 0; i4_j < ps_layer_mv->i4_num_mvs_per_ref; i4_j++)
{
hme_add_new_node_to_a_sorted_array(
&ps_search_node_4x4[i4_j],
pps_result_nodes,
pu1_cost_shifts_for_sorted_node,
*pu4_num_results_updated,
0);
(*pu4_num_results_updated)++;
hme_add_new_node_to_a_sorted_array(
&ps_search_node_8x8[i4_j],
pps_result_nodes,
pu1_cost_shifts_for_sorted_node,
*pu4_num_results_updated,
2);
(*pu4_num_results_updated)++;
}
}
switch(i)
{
case 0:
{
ps_mv_l0_root = ps_mv1_l0_root;
ps_mv_l1_root = ps_mv1_l1_root;
pi1_ref_idx_l0_root = pi1_ref_idx1_l0_root;
pi1_ref_idx_l1_root = pi1_ref_idx1_l1_root;
break;
}
case 1:
{
ps_mv_l0_root = ps_mv2_l0_root;
ps_mv_l1_root = ps_mv2_l1_root;
pi1_ref_idx_l0_root = pi1_ref_idx2_l0_root;
pi1_ref_idx_l1_root = pi1_ref_idx2_l1_root;
break;
}
case 2:
{
ps_mv_l0_root = ps_mv3_l0_root;
ps_mv_l1_root = ps_mv3_l1_root;
pi1_ref_idx_l0_root = pi1_ref_idx3_l0_root;
pi1_ref_idx_l1_root = pi1_ref_idx3_l1_root;
break;
}
case 3:
{
ps_mv_l0_root = ps_mv4_l0_root;
ps_mv_l1_root = ps_mv4_l1_root;
pi1_ref_idx_l0_root = pi1_ref_idx4_l0_root;
pi1_ref_idx_l1_root = pi1_ref_idx4_l1_root;
break;
}
}
u4_num_l0_results_updated =
MIN((S32)u4_num_l0_results_updated,
ps_prms->i4_num_active_ref_l0 * ps_layer_mv->i4_num_mvs_per_ref);
u4_num_l1_results_updated =
MIN((S32)u4_num_l1_results_updated,
ps_prms->i4_num_active_ref_l1 * ps_layer_mv->i4_num_mvs_per_ref);
for(i4_j = 0; i4_j < (S32)u4_num_l0_results_updated; i4_j++)
{
COPY_SEARCH_RESULT(
&ps_mv_l0_root[i4_j],
&pi1_ref_idx_l0_root[i4_j],
aps_result_nodes_sorted[0][i4_j],
0);
}
for(i4_j = 0; i4_j < (S32)u4_num_l1_results_updated; i4_j++)
{
COPY_SEARCH_RESULT(
&ps_mv_l1_root[i4_j],
&pi1_ref_idx_l1_root[i4_j],
aps_result_nodes_sorted[1][i4_j],
0);
}
}
}
}
/**
******************************************************************************
* @brief Scales motion vector component projecte from a diff layer in same
* picture (so no ref id related delta poc scaling required)
******************************************************************************
*/
#define SCALE_MV_COMP_RES(mvcomp_p, dim_c, dim_p) \
((((mvcomp_p) * (dim_c)) + ((SIGN((mvcomp_p)) * (dim_p)) >> 1)) / (dim_p))
/**
********************************************************************************
* @fn hme_project_coloc_candt(search_node_t *ps_search_node,
* layer_ctxt_t *ps_curr_layer,
* layer_ctxt_t *ps_coarse_layer,
* S32 i4_pos_x,
* S32 i4_pos_y,
* S08 i1_ref_id,
* S08 i1_result_id)
*
* @brief From a coarser layer, projects a candidated situated at "colocated"
* position in the picture (e.g. given x, y it will be x/2, y/2 dyadic
*
* @param[out] ps_search_node : contains the projected result
*
* @param[in] ps_curr_layer : current layer context
*
* @param[in] ps_coarse_layer : coarser layer context
*
* @param[in] i4_pos_x : x Position where mv is required (w.r.t. curr layer)
*
* @param[in] i4_pos_y : y Position where mv is required (w.r.t. curr layer)
*
* @param[in] i1_ref_id : reference id for which the candidate required
*
* @param[in] i4_result_id : result id for which the candidate required
* (0 : best result, 1 : next best)
*
* @return None
********************************************************************************
*/
void hme_project_coloc_candt(
search_node_t *ps_search_node,
layer_ctxt_t *ps_curr_layer,
layer_ctxt_t *ps_coarse_layer,
S32 i4_pos_x,
S32 i4_pos_y,
S08 i1_ref_id,
S32 i4_result_id)
{
S32 wd_c, ht_c, wd_p, ht_p;
S32 blksize_p, blk_x, blk_y, i4_offset;
layer_mv_t *ps_layer_mvbank;
hme_mv_t *ps_mv;
S08 *pi1_ref_idx;
/* Width and ht of current and prev layers */
wd_c = ps_curr_layer->i4_wd;
ht_c = ps_curr_layer->i4_ht;
wd_p = ps_coarse_layer->i4_wd;
ht_p = ps_coarse_layer->i4_ht;
ps_layer_mvbank = ps_coarse_layer->ps_layer_mvbank;
blksize_p = (S32)gau1_blk_size_to_wd[ps_layer_mvbank->e_blk_size];
/* Safety check to avoid uninitialized access across temporal layers */
i4_pos_x = CLIP3(i4_pos_x, 0, (wd_c - blksize_p));
i4_pos_y = CLIP3(i4_pos_y, 0, (ht_c - blksize_p));
/* Project the positions to prev layer */
/* TODO: convert these to scale factors at pic level */
blk_x = (i4_pos_x * wd_p) / (wd_c * blksize_p);
blk_y = (i4_pos_y * ht_p) / (ht_c * blksize_p);
/* Pick up the mvs from the location */
i4_offset = (blk_x * ps_layer_mvbank->i4_num_mvs_per_blk);
i4_offset += (ps_layer_mvbank->i4_num_mvs_per_row * blk_y);
ps_mv = ps_layer_mvbank->ps_mv + i4_offset;
pi1_ref_idx = ps_layer_mvbank->pi1_ref_idx + i4_offset;
ps_mv += (i1_ref_id * ps_layer_mvbank->i4_num_mvs_per_ref);
pi1_ref_idx += (i1_ref_id * ps_layer_mvbank->i4_num_mvs_per_ref);
ps_search_node->s_mv.i2_mvx = SCALE_MV_COMP_RES(ps_mv[i4_result_id].i2_mv_x, wd_c, wd_p);
ps_search_node->s_mv.i2_mvy = SCALE_MV_COMP_RES(ps_mv[i4_result_id].i2_mv_y, ht_c, ht_p);
ps_search_node->i1_ref_idx = pi1_ref_idx[i4_result_id];
ps_search_node->u1_subpel_done = 0;
if((ps_search_node->i1_ref_idx < 0) || (ps_search_node->s_mv.i2_mvx == INTRA_MV))
{
ps_search_node->i1_ref_idx = i1_ref_id;
ps_search_node->s_mv.i2_mvx = 0;
ps_search_node->s_mv.i2_mvy = 0;
}
}
/**
********************************************************************************
* @fn hme_project_coloc_candt_dyadic(search_node_t *ps_search_node,
* layer_ctxt_t *ps_curr_layer,
* layer_ctxt_t *ps_coarse_layer,
* S32 i4_pos_x,
* S32 i4_pos_y,
* S08 i1_ref_id,
* S08 i1_result_id)
*
* @brief From a coarser layer, projects a candidated situated at "colocated"
* position in the picture when the ratios are dyadic
*
* @param[out] ps_search_node : contains the projected result
*
* @param[in] ps_curr_layer : current layer context
*
* @param[in] ps_coarse_layer : coarser layer context
*
* @param[in] i4_pos_x : x Position where mv is required (w.r.t. curr layer)
*
* @param[in] i4_pos_y : y Position where mv is required (w.r.t. curr layer)
*
* @param[in] i1_ref_id : reference id for which the candidate required
*
* @param[in] i4_result_id : result id for which the candidate required
* (0 : best result, 1 : next best)
*
* @return None
********************************************************************************
*/
void hme_project_coloc_candt_dyadic(
search_node_t *ps_search_node,
layer_ctxt_t *ps_curr_layer,
layer_ctxt_t *ps_coarse_layer,
S32 i4_pos_x,
S32 i4_pos_y,
S08 i1_ref_id,
S32 i4_result_id)
{
S32 wd_c, ht_c, wd_p, ht_p;
S32 blksize_p, blk_x, blk_y, i4_offset;
layer_mv_t *ps_layer_mvbank;
hme_mv_t *ps_mv;
S08 *pi1_ref_idx;
/* Width and ht of current and prev layers */
wd_c = ps_curr_layer->i4_wd;
ht_c = ps_curr_layer->i4_ht;
wd_p = ps_coarse_layer->i4_wd;
ht_p = ps_coarse_layer->i4_ht;
ps_layer_mvbank = ps_coarse_layer->ps_layer_mvbank;
/* blksize_p = log2(wd) + 1 */
blksize_p = (S32)gau1_blk_size_to_wd_shift[ps_layer_mvbank->e_blk_size];
/* ASSERT for valid sizes */
ASSERT((blksize_p == 3) || (blksize_p == 4) || (blksize_p == 5));
/* Safety check to avoid uninitialized access across temporal layers */
i4_pos_x = CLIP3(i4_pos_x, 0, (wd_c - blksize_p));
i4_pos_y = CLIP3(i4_pos_y, 0, (ht_c - blksize_p));
/* Project the positions to prev layer */
/* TODO: convert these to scale factors at pic level */
blk_x = i4_pos_x >> blksize_p; // (2 * blksize_p);
blk_y = i4_pos_y >> blksize_p; // (2 * blksize_p);
/* Pick up the mvs from the location */
i4_offset = (blk_x * ps_layer_mvbank->i4_num_mvs_per_blk);
i4_offset += (ps_layer_mvbank->i4_num_mvs_per_row * blk_y);
ps_mv = ps_layer_mvbank->ps_mv + i4_offset;
pi1_ref_idx = ps_layer_mvbank->pi1_ref_idx + i4_offset;
ps_mv += (i1_ref_id * ps_layer_mvbank->i4_num_mvs_per_ref);
pi1_ref_idx += (i1_ref_id * ps_layer_mvbank->i4_num_mvs_per_ref);
ps_search_node->s_mv.i2_mvx = ps_mv[i4_result_id].i2_mv_x << 1;
ps_search_node->s_mv.i2_mvy = ps_mv[i4_result_id].i2_mv_y << 1;
ps_search_node->i1_ref_idx = pi1_ref_idx[i4_result_id];
if((ps_search_node->i1_ref_idx < 0) || (ps_search_node->s_mv.i2_mvx == INTRA_MV))
{
ps_search_node->i1_ref_idx = i1_ref_id;
ps_search_node->s_mv.i2_mvx = 0;
ps_search_node->s_mv.i2_mvy = 0;
}
}
void hme_project_coloc_candt_dyadic_implicit(
search_node_t *ps_search_node,
layer_ctxt_t *ps_curr_layer,
layer_ctxt_t *ps_coarse_layer,
S32 i4_pos_x,
S32 i4_pos_y,
S32 i4_num_act_ref_l0,
U08 u1_pred_dir,
U08 u1_default_ref_id,
S32 i4_result_id)
{
S32 wd_c, ht_c, wd_p, ht_p;
S32 blksize_p, blk_x, blk_y, i4_offset;
layer_mv_t *ps_layer_mvbank;
hme_mv_t *ps_mv;
S08 *pi1_ref_idx;
/* Width and ht of current and prev layers */
wd_c = ps_curr_layer->i4_wd;
ht_c = ps_curr_layer->i4_ht;
wd_p = ps_coarse_layer->i4_wd;
ht_p = ps_coarse_layer->i4_ht;
ps_layer_mvbank = ps_coarse_layer->ps_layer_mvbank;
blksize_p = (S32)gau1_blk_size_to_wd_shift[ps_layer_mvbank->e_blk_size];
/* ASSERT for valid sizes */
ASSERT((blksize_p == 3) || (blksize_p == 4) || (blksize_p == 5));
/* Safety check to avoid uninitialized access across temporal layers */
i4_pos_x = CLIP3(i4_pos_x, 0, (wd_c - blksize_p));
i4_pos_y = CLIP3(i4_pos_y, 0, (ht_c - blksize_p));
/* Project the positions to prev layer */
/* TODO: convert these to scale factors at pic level */
blk_x = i4_pos_x >> blksize_p; // (2 * blksize_p);
blk_y = i4_pos_y >> blksize_p; // (2 * blksize_p);
/* Pick up the mvs from the location */
i4_offset = (blk_x * ps_layer_mvbank->i4_num_mvs_per_blk);
i4_offset += (ps_layer_mvbank->i4_num_mvs_per_row * blk_y);
ps_mv = ps_layer_mvbank->ps_mv + i4_offset;
pi1_ref_idx = ps_layer_mvbank->pi1_ref_idx + i4_offset;
if(u1_pred_dir == 1)
{
ps_mv += (i4_num_act_ref_l0 * ps_layer_mvbank->i4_num_mvs_per_ref);
pi1_ref_idx += (i4_num_act_ref_l0 * ps_layer_mvbank->i4_num_mvs_per_ref);
}
ps_search_node->s_mv.i2_mvx = ps_mv[i4_result_id].i2_mv_x << 1;
ps_search_node->s_mv.i2_mvy = ps_mv[i4_result_id].i2_mv_y << 1;
ps_search_node->i1_ref_idx = pi1_ref_idx[i4_result_id];
if((ps_search_node->i1_ref_idx < 0) || (ps_search_node->s_mv.i2_mvx == INTRA_MV))
{
ps_search_node->i1_ref_idx = u1_default_ref_id;
ps_search_node->s_mv.i2_mvx = 0;
ps_search_node->s_mv.i2_mvy = 0;
}
}
#define SCALE_RANGE_PRMS(prm1, prm2, shift) \
{ \
prm1.i2_min_x = prm2.i2_min_x << shift; \
prm1.i2_max_x = prm2.i2_max_x << shift; \
prm1.i2_min_y = prm2.i2_min_y << shift; \
prm1.i2_max_y = prm2.i2_max_y << shift; \
}
#define SCALE_RANGE_PRMS_POINTERS(prm1, prm2, shift) \
{ \
prm1->i2_min_x = prm2->i2_min_x << shift; \
prm1->i2_max_x = prm2->i2_max_x << shift; \
prm1->i2_min_y = prm2->i2_min_y << shift; \
prm1->i2_max_y = prm2->i2_max_y << shift; \
}
/**
********************************************************************************
* @fn void hme_refine_frm_init(me_ctxt_t *ps_ctxt,
* refine_layer_prms_t *ps_refine_prms)
*
* @brief Frame init of refinemnet layers in ME
*
* @param[in,out] ps_ctxt: ME Handle
*
* @param[in] ps_refine_prms : refinement layer prms
*
* @return None
********************************************************************************
*/
void hme_refine_frm_init(
layer_ctxt_t *ps_curr_layer, refine_prms_t *ps_refine_prms, layer_ctxt_t *ps_coarse_layer)
{
/* local variables */
BLK_SIZE_T e_result_blk_size = BLK_8x8;
S32 i4_num_ref_fpel, i4_num_ref_prev_layer;
i4_num_ref_prev_layer = ps_coarse_layer->ps_layer_mvbank->i4_num_ref;
if(ps_refine_prms->explicit_ref)
{
i4_num_ref_fpel = i4_num_ref_prev_layer;
}
else
{
i4_num_ref_fpel = 2;
}
if(ps_refine_prms->i4_enable_4x4_part)
{
e_result_blk_size = BLK_4x4;
}
i4_num_ref_fpel = MIN(i4_num_ref_fpel, i4_num_ref_prev_layer);
hme_init_mv_bank(
ps_curr_layer,
e_result_blk_size,
i4_num_ref_fpel,
ps_refine_prms->i4_num_mvbank_results,
ps_refine_prms->i4_layer_id > 0 ? 0 : 1);
}
#if 1 //ENABLE_CU_RECURSION || TEST_AND_EVALUATE_CU_RECURSION
/**
********************************************************************************
* @fn void hme_init_clusters_16x16
* (
* cluster_16x16_blk_t *ps_cluster_blk_16x16
* )
*
* @brief Intialisations for the structs used in clustering algorithm
*
* @param[in/out] ps_cluster_blk_16x16: pointer to structure containing clusters
* of 16x16 block
*
* @return None
********************************************************************************
*/
static __inline void
hme_init_clusters_16x16(cluster_16x16_blk_t *ps_cluster_blk_16x16, S32 bidir_enabled)
{
S32 i;
ps_cluster_blk_16x16->num_clusters = 0;
ps_cluster_blk_16x16->intra_mv_area = 0;
ps_cluster_blk_16x16->best_inter_cost = 0;
for(i = 0; i < MAX_NUM_CLUSTERS_16x16; i++)
{
ps_cluster_blk_16x16->as_cluster_data[i].max_dist_from_centroid =
bidir_enabled ? MAX_DISTANCE_FROM_CENTROID_16x16_B : MAX_DISTANCE_FROM_CENTROID_16x16;
ps_cluster_blk_16x16->as_cluster_data[i].is_valid_cluster = 0;
ps_cluster_blk_16x16->as_cluster_data[i].bi_mv_pixel_area = 0;
ps_cluster_blk_16x16->as_cluster_data[i].uni_mv_pixel_area = 0;
}
for(i = 0; i < MAX_NUM_REF; i++)
{
ps_cluster_blk_16x16->au1_num_clusters[i] = 0;
}
}
/**
********************************************************************************
* @fn void hme_init_clusters_32x32
* (
* cluster_32x32_blk_t *ps_cluster_blk_32x32
* )
*
* @brief Intialisations for the structs used in clustering algorithm
*
* @param[in/out] ps_cluster_blk_32x32: pointer to structure containing clusters
* of 32x32 block
*
* @return None
********************************************************************************
*/
static __inline void
hme_init_clusters_32x32(cluster_32x32_blk_t *ps_cluster_blk_32x32, S32 bidir_enabled)
{
S32 i;
ps_cluster_blk_32x32->num_clusters = 0;
ps_cluster_blk_32x32->intra_mv_area = 0;
ps_cluster_blk_32x32->best_alt_ref = -1;
ps_cluster_blk_32x32->best_uni_ref = -1;
ps_cluster_blk_32x32->best_inter_cost = 0;
ps_cluster_blk_32x32->num_clusters_with_weak_sdi_density = 0;
for(i = 0; i < MAX_NUM_CLUSTERS_32x32; i++)
{
ps_cluster_blk_32x32->as_cluster_data[i].max_dist_from_centroid =
bidir_enabled ? MAX_DISTANCE_FROM_CENTROID_32x32_B : MAX_DISTANCE_FROM_CENTROID_32x32;
ps_cluster_blk_32x32->as_cluster_data[i].is_valid_cluster = 0;
ps_cluster_blk_32x32->as_cluster_data[i].bi_mv_pixel_area = 0;
ps_cluster_blk_32x32->as_cluster_data[i].uni_mv_pixel_area = 0;
}
for(i = 0; i < MAX_NUM_REF; i++)
{
ps_cluster_blk_32x32->au1_num_clusters[i] = 0;
}
}
/**
********************************************************************************
* @fn void hme_init_clusters_64x64
* (
* cluster_64x64_blk_t *ps_cluster_blk_64x64
* )
*
* @brief Intialisations for the structs used in clustering algorithm
*
* @param[in/out] ps_cluster_blk_64x64: pointer to structure containing clusters
* of 64x64 block
*
* @return None
********************************************************************************
*/
static __inline void
hme_init_clusters_64x64(cluster_64x64_blk_t *ps_cluster_blk_64x64, S32 bidir_enabled)
{
S32 i;
ps_cluster_blk_64x64->num_clusters = 0;
ps_cluster_blk_64x64->intra_mv_area = 0;
ps_cluster_blk_64x64->best_alt_ref = -1;
ps_cluster_blk_64x64->best_uni_ref = -1;
ps_cluster_blk_64x64->best_inter_cost = 0;
for(i = 0; i < MAX_NUM_CLUSTERS_64x64; i++)
{
ps_cluster_blk_64x64->as_cluster_data[i].max_dist_from_centroid =
bidir_enabled ? MAX_DISTANCE_FROM_CENTROID_64x64_B : MAX_DISTANCE_FROM_CENTROID_64x64;
ps_cluster_blk_64x64->as_cluster_data[i].is_valid_cluster = 0;
ps_cluster_blk_64x64->as_cluster_data[i].bi_mv_pixel_area = 0;
ps_cluster_blk_64x64->as_cluster_data[i].uni_mv_pixel_area = 0;
}
for(i = 0; i < MAX_NUM_REF; i++)
{
ps_cluster_blk_64x64->au1_num_clusters[i] = 0;
}
}
/**
********************************************************************************
* @fn void hme_sort_and_assign_top_ref_ids_areawise
* (
* ctb_cluster_info_t *ps_ctb_cluster_info
* )
*
* @brief Finds best_uni_ref and best_alt_ref
*
* @param[in/out] ps_ctb_cluster_info: structure that points to ctb data
*
* @param[in] bidir_enabled: flag that indicates whether or not bi-pred is
* enabled
*
* @param[in] block_width: width of the block in pels
*
* @param[in] e_cu_pos: position of the block within the CTB
*
* @return None
********************************************************************************
*/
void hme_sort_and_assign_top_ref_ids_areawise(
ctb_cluster_info_t *ps_ctb_cluster_info, S32 bidir_enabled, S32 block_width, CU_POS_T e_cu_pos)
{
cluster_32x32_blk_t *ps_32x32 = NULL;
cluster_64x64_blk_t *ps_64x64 = NULL;
cluster_data_t *ps_data;
S32 j, k;
S32 ai4_uni_area[MAX_NUM_REF];
S32 ai4_bi_area[MAX_NUM_REF];
S32 ai4_ref_id_found[MAX_NUM_REF];
S32 ai4_ref_id[MAX_NUM_REF];
S32 best_uni_ref = -1, best_alt_ref = -1;
S32 num_clusters;
S32 num_ref = 0;
S32 num_clusters_evaluated = 0;
S32 is_cur_blk_valid;
if(32 == block_width)
{
is_cur_blk_valid = (ps_ctb_cluster_info->blk_32x32_mask & (1 << e_cu_pos)) || 0;
ps_32x32 = &ps_ctb_cluster_info->ps_32x32_blk[e_cu_pos];
num_clusters = ps_32x32->num_clusters;
ps_data = &ps_32x32->as_cluster_data[0];
}
else
{
is_cur_blk_valid = (ps_ctb_cluster_info->blk_32x32_mask == 0xf);
ps_64x64 = ps_ctb_cluster_info->ps_64x64_blk;
num_clusters = ps_64x64->num_clusters;
ps_data = &ps_64x64->as_cluster_data[0];
}
#if !ENABLE_4CTB_EVALUATION
if((num_clusters > MAX_NUM_CLUSTERS_IN_VALID_32x32_BLK))
{
return;
}
#endif
if(num_clusters == 0)
{
return;
}
else if(!is_cur_blk_valid)
{
return;
}
memset(ai4_uni_area, 0, sizeof(S32) * MAX_NUM_REF);
memset(ai4_bi_area, 0, sizeof(S32) * MAX_NUM_REF);
memset(ai4_ref_id_found, 0, sizeof(S32) * MAX_NUM_REF);
memset(ai4_ref_id, -1, sizeof(S32) * MAX_NUM_REF);
for(j = 0; num_clusters_evaluated < num_clusters; j++, ps_data++)
{
S32 ref_id;
if(!ps_data->is_valid_cluster)
{
continue;
}
ref_id = ps_data->ref_id;
num_clusters_evaluated++;
ai4_uni_area[ref_id] += ps_data->uni_mv_pixel_area;
ai4_bi_area[ref_id] += ps_data->bi_mv_pixel_area;
if(!ai4_ref_id_found[ref_id])
{
ai4_ref_id[ref_id] = ref_id;
ai4_ref_id_found[ref_id] = 1;
num_ref++;
}
}
{
S32 ai4_ref_id_temp[MAX_NUM_REF];
memcpy(ai4_ref_id_temp, ai4_ref_id, sizeof(S32) * MAX_NUM_REF);
for(k = 1; k < MAX_NUM_REF; k++)
{
if(ai4_uni_area[k] > ai4_uni_area[0])
{
SWAP_HME(ai4_uni_area[k], ai4_uni_area[0], S32);
SWAP_HME(ai4_ref_id_temp[k], ai4_ref_id_temp[0], S32);
}
}
best_uni_ref = ai4_ref_id_temp[0];
}
if(bidir_enabled)
{
for(k = 1; k < MAX_NUM_REF; k++)
{
if(ai4_bi_area[k] > ai4_bi_area[0])
{
SWAP_HME(ai4_bi_area[k], ai4_bi_area[0], S32);
SWAP_HME(ai4_ref_id[k], ai4_ref_id[0], S32);
}
}
if(!ai4_bi_area[0])
{
best_alt_ref = -1;
if(32 == block_width)
{
SET_VALUES_FOR_TOP_REF_IDS(ps_32x32, best_uni_ref, best_alt_ref, num_ref);
}
else
{
SET_VALUES_FOR_TOP_REF_IDS(ps_64x64, best_uni_ref, best_alt_ref, num_ref);
}
return;
}
if(best_uni_ref == ai4_ref_id[0])
{
for(k = 2; k < MAX_NUM_REF; k++)
{
if(ai4_bi_area[k] > ai4_bi_area[1])
{
SWAP_HME(ai4_bi_area[k], ai4_bi_area[1], S32);
SWAP_HME(ai4_ref_id[k], ai4_ref_id[1], S32);
}
}
best_alt_ref = ai4_ref_id[1];
}
else
{
best_alt_ref = ai4_ref_id[0];
}
}
if(32 == block_width)
{
SET_VALUES_FOR_TOP_REF_IDS(ps_32x32, best_uni_ref, best_alt_ref, num_ref);
}
else
{
SET_VALUES_FOR_TOP_REF_IDS(ps_64x64, best_uni_ref, best_alt_ref, num_ref);
}
}
/**
********************************************************************************
* @fn void hme_find_top_ref_ids
* (
* ctb_cluster_info_t *ps_ctb_cluster_info
* )
*
* @brief Finds best_uni_ref and best_alt_ref
*
* @param[in/out] ps_ctb_cluster_info: structure that points to ctb data
*
* @return None
********************************************************************************
*/
void hme_find_top_ref_ids(
ctb_cluster_info_t *ps_ctb_cluster_info, S32 bidir_enabled, S32 block_width)
{
S32 i;
if(32 == block_width)
{
for(i = 0; i < 4; i++)
{
hme_sort_and_assign_top_ref_ids_areawise(
ps_ctb_cluster_info, bidir_enabled, block_width, (CU_POS_T)i);
}
}
else if(64 == block_width)
{
hme_sort_and_assign_top_ref_ids_areawise(
ps_ctb_cluster_info, bidir_enabled, block_width, POS_NA);
}
}
/**
********************************************************************************
* @fn void hme_boot_out_outlier
* (
* ctb_cluster_info_t *ps_ctb_cluster_info
* )
*
* @brief Removes outlier clusters before CU tree population
*
* @param[in/out] ps_ctb_cluster_info: structure that points to ctb data
*
* @return None
********************************************************************************
*/
void hme_boot_out_outlier(ctb_cluster_info_t *ps_ctb_cluster_info, S32 blk_width)
{
cluster_32x32_blk_t *ps_32x32;
S32 i;
cluster_64x64_blk_t *ps_64x64 = &ps_ctb_cluster_info->ps_64x64_blk[0];
S32 sdi_threshold = ps_ctb_cluster_info->sdi_threshold;
if(32 == blk_width)
{
/* 32x32 clusters */
for(i = 0; i < 4; i++)
{
ps_32x32 = &ps_ctb_cluster_info->ps_32x32_blk[i];
if(ps_32x32->num_clusters > MAX_NUM_CLUSTERS_IN_ONE_REF_IDX)
{
BUMP_OUTLIER_CLUSTERS(ps_32x32, sdi_threshold);
}
}
}
else if(64 == blk_width)
{
/* 64x64 clusters */
if(ps_64x64->num_clusters > MAX_NUM_CLUSTERS_IN_ONE_REF_IDX)
{
BUMP_OUTLIER_CLUSTERS(ps_64x64, sdi_threshold);
}
}
}
/**
********************************************************************************
* @fn void hme_update_cluster_attributes
* (
* cluster_data_t *ps_cluster_data,
* S32 mvx,
* S32 mvy,
* PART_ID_T e_part_id
* )
*
* @brief Implementation fo the clustering algorithm
*
* @param[in/out] ps_cluster_data: pointer to cluster_data_t struct
*
* @param[in] mvx : x co-ordinate of the motion vector
*
* @param[in] mvy : y co-ordinate of the motion vector
*
* @param[in] ref_idx : ref_id of the motion vector
*
* @param[in] e_part_id : partition id of the motion vector
*
* @return None
********************************************************************************
*/
static __inline void hme_update_cluster_attributes(
cluster_data_t *ps_cluster_data,
S32 mvx,
S32 mvy,
S32 mvdx,
S32 mvdy,
S32 ref_id,
S32 sdi,
U08 is_part_of_bi,
PART_ID_T e_part_id)
{
LWORD64 i8_mvx_sum_q8;
LWORD64 i8_mvy_sum_q8;
S32 centroid_posx_q8 = ps_cluster_data->s_centroid.i4_pos_x_q8;
S32 centroid_posy_q8 = ps_cluster_data->s_centroid.i4_pos_y_q8;
if((mvdx > 0) && (ps_cluster_data->min_x > mvx))
{
ps_cluster_data->min_x = mvx;
}
else if((mvdx < 0) && (ps_cluster_data->max_x < mvx))
{
ps_cluster_data->max_x = mvx;
}
if((mvdy > 0) && (ps_cluster_data->min_y > mvy))
{
ps_cluster_data->min_y = mvy;
}
else if((mvdy < 0) && (ps_cluster_data->max_y < mvy))
{
ps_cluster_data->max_y = mvy;
}
{
S32 num_mvs = ps_cluster_data->num_mvs;
ps_cluster_data->as_mv[num_mvs].pixel_count = gai4_partition_area[e_part_id];
ps_cluster_data->as_mv[num_mvs].mvx = mvx;
ps_cluster_data->as_mv[num_mvs].mvy = mvy;
/***************************/
ps_cluster_data->as_mv[num_mvs].is_uni = !is_part_of_bi;
ps_cluster_data->as_mv[num_mvs].sdi = sdi;
/**************************/
}
/* Updation of centroid */
{
i8_mvx_sum_q8 = (LWORD64)centroid_posx_q8 * ps_cluster_data->num_mvs + (mvx << 8);
i8_mvy_sum_q8 = (LWORD64)centroid_posy_q8 * ps_cluster_data->num_mvs + (mvy << 8);
ps_cluster_data->num_mvs++;
ps_cluster_data->s_centroid.i4_pos_x_q8 =
(WORD32)((i8_mvx_sum_q8) / ps_cluster_data->num_mvs);
ps_cluster_data->s_centroid.i4_pos_y_q8 =
(WORD32)((i8_mvy_sum_q8) / ps_cluster_data->num_mvs);
}
ps_cluster_data->area_in_pixels += gai4_partition_area[e_part_id];
if(is_part_of_bi)
{
ps_cluster_data->bi_mv_pixel_area += gai4_partition_area[e_part_id];
}
else
{
ps_cluster_data->uni_mv_pixel_area += gai4_partition_area[e_part_id];
}
}
/**
********************************************************************************
* @fn void hme_try_cluster_merge
* (
* cluster_data_t *ps_cluster_data,
* S32 *pi4_num_clusters,
* S32 idx_of_updated_cluster
* )
*
* @brief Implementation fo the clustering algorithm
*
* @param[in/out] ps_cluster_data: pointer to cluster_data_t struct
*
* @param[in/out] pi4_num_clusters : pointer to number of clusters
*
* @param[in] idx_of_updated_cluster : index of the cluster most recently
* updated
*
* @return Nothing
********************************************************************************
*/
void hme_try_cluster_merge(
cluster_data_t *ps_cluster_data, U08 *pu1_num_clusters, S32 idx_of_updated_cluster)
{
centroid_t *ps_centroid;
S32 cur_pos_x_q8;
S32 cur_pos_y_q8;
S32 i;
S32 max_dist_from_centroid;
S32 mvd;
S32 mvdx_q8;
S32 mvdx;
S32 mvdy_q8;
S32 mvdy;
S32 num_clusters, num_clusters_evaluated;
S32 other_pos_x_q8;
S32 other_pos_y_q8;
cluster_data_t *ps_root = ps_cluster_data;
cluster_data_t *ps_cur_cluster = &ps_cluster_data[idx_of_updated_cluster];
centroid_t *ps_cur_centroid = &ps_cur_cluster->s_centroid;
/* Merge is superfluous if num_clusters is 1 */
if(*pu1_num_clusters == 1)
{
return;
}
cur_pos_x_q8 = ps_cur_centroid->i4_pos_x_q8;
cur_pos_y_q8 = ps_cur_centroid->i4_pos_y_q8;
max_dist_from_centroid = ps_cur_cluster->max_dist_from_centroid;
num_clusters = *pu1_num_clusters;
num_clusters_evaluated = 0;
for(i = 0; num_clusters_evaluated < num_clusters; i++, ps_cluster_data++)
{
if(!ps_cluster_data->is_valid_cluster)
{
continue;
}
if((ps_cluster_data->ref_id != ps_cur_cluster->ref_id) || (i == idx_of_updated_cluster))
{
num_clusters_evaluated++;
continue;
}
ps_centroid = &ps_cluster_data->s_centroid;
other_pos_x_q8 = ps_centroid->i4_pos_x_q8;
other_pos_y_q8 = ps_centroid->i4_pos_y_q8;
mvdx_q8 = (cur_pos_x_q8 - other_pos_x_q8);
mvdy_q8 = (cur_pos_y_q8 - other_pos_y_q8);
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = ABS(mvdx) + ABS(mvdy);
if(mvd <= (max_dist_from_centroid >> 1))
{
/* 0 => no updates */
/* 1 => min updated */
/* 2 => max updated */
S32 minmax_x_update_id;
S32 minmax_y_update_id;
LWORD64 i8_mv_x_sum_self = (LWORD64)cur_pos_x_q8 * ps_cur_cluster->num_mvs;
LWORD64 i8_mv_y_sum_self = (LWORD64)cur_pos_y_q8 * ps_cur_cluster->num_mvs;
LWORD64 i8_mv_x_sum_cousin = (LWORD64)other_pos_x_q8 * ps_cluster_data->num_mvs;
LWORD64 i8_mv_y_sum_cousin = (LWORD64)other_pos_y_q8 * ps_cluster_data->num_mvs;
(*pu1_num_clusters)--;
ps_cluster_data->is_valid_cluster = 0;
memcpy(
&ps_cur_cluster->as_mv[ps_cur_cluster->num_mvs],
ps_cluster_data->as_mv,
sizeof(mv_data_t) * ps_cluster_data->num_mvs);
ps_cur_cluster->num_mvs += ps_cluster_data->num_mvs;
ps_cur_cluster->area_in_pixels += ps_cluster_data->area_in_pixels;
ps_cur_cluster->bi_mv_pixel_area += ps_cluster_data->bi_mv_pixel_area;
ps_cur_cluster->uni_mv_pixel_area += ps_cluster_data->uni_mv_pixel_area;
i8_mv_x_sum_self += i8_mv_x_sum_cousin;
i8_mv_y_sum_self += i8_mv_y_sum_cousin;
ps_cur_centroid->i4_pos_x_q8 = (WORD32)(i8_mv_x_sum_self / ps_cur_cluster->num_mvs);
ps_cur_centroid->i4_pos_y_q8 = (WORD32)(i8_mv_y_sum_self / ps_cur_cluster->num_mvs);
minmax_x_update_id = (ps_cur_cluster->min_x < ps_cluster_data->min_x)
? ((ps_cur_cluster->max_x > ps_cluster_data->max_x) ? 0 : 2)
: 1;
minmax_y_update_id = (ps_cur_cluster->min_y < ps_cluster_data->min_y)
? ((ps_cur_cluster->max_y > ps_cluster_data->max_y) ? 0 : 2)
: 1;
/* Updation of centroid spread */
switch(minmax_x_update_id + (minmax_y_update_id << 2))
{
case 1:
{
S32 mvd, mvd_q8;
ps_cur_cluster->min_x = ps_cluster_data->min_x;
mvd_q8 = ps_centroid->i4_pos_x_q8 - (ps_cur_cluster->min_x << 8);
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (max_dist_from_centroid))
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 2:
{
S32 mvd, mvd_q8;
ps_cur_cluster->max_x = ps_cluster_data->max_x;
mvd_q8 = (ps_cur_cluster->max_x << 8) - ps_centroid->i4_pos_x_q8;
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (max_dist_from_centroid))
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 4:
{
S32 mvd, mvd_q8;
ps_cur_cluster->min_y = ps_cluster_data->min_y;
mvd_q8 = ps_centroid->i4_pos_y_q8 - (ps_cur_cluster->min_y << 8);
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (max_dist_from_centroid))
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 5:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdy_q8 = ps_centroid->i4_pos_y_q8 - (ps_cur_cluster->min_y << 8);
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvdx_q8 = ps_centroid->i4_pos_x_q8 - (ps_cur_cluster->min_x << 8);
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
ps_cur_cluster->min_x = ps_cluster_data->min_x;
ps_cur_cluster->min_y = ps_cluster_data->min_y;
if(mvd > max_dist_from_centroid)
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 6:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdy_q8 = ps_centroid->i4_pos_y_q8 - (ps_cur_cluster->min_y << 8);
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvdx_q8 = (ps_cur_cluster->max_x << 8) - ps_centroid->i4_pos_x_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
ps_cur_cluster->max_x = ps_cluster_data->max_x;
ps_cur_cluster->min_y = ps_cluster_data->min_y;
if(mvd > max_dist_from_centroid)
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 8:
{
S32 mvd, mvd_q8;
ps_cur_cluster->max_y = ps_cluster_data->max_y;
mvd_q8 = (ps_cur_cluster->max_y << 8) - ps_centroid->i4_pos_y_q8;
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (max_dist_from_centroid))
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 9:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdx_q8 = ps_centroid->i4_pos_x_q8 - (ps_cur_cluster->min_x << 8);
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy_q8 = (ps_cur_cluster->max_y << 8) - ps_centroid->i4_pos_y_q8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
ps_cur_cluster->min_x = ps_cluster_data->min_x;
ps_cur_cluster->max_y = ps_cluster_data->max_y;
if(mvd > max_dist_from_centroid)
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 10:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdx_q8 = (ps_cur_cluster->max_x << 8) - ps_centroid->i4_pos_x_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy_q8 = (ps_cur_cluster->max_y << 8) - ps_centroid->i4_pos_y_q8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
ps_cur_cluster->max_x = ps_cluster_data->max_x;
ps_cur_cluster->max_y = ps_cluster_data->max_y;
if(mvd > ps_cluster_data->max_dist_from_centroid)
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
default:
{
break;
}
}
hme_try_cluster_merge(ps_root, pu1_num_clusters, idx_of_updated_cluster);
return;
}
num_clusters_evaluated++;
}
}
/**
********************************************************************************
* @fn void hme_find_and_update_clusters
* (
* cluster_data_t *ps_cluster_data,
* S32 *pi4_num_clusters,
* S32 mvx,
* S32 mvy,
* S32 ref_idx,
* PART_ID_T e_part_id
* )
*
* @brief Implementation fo the clustering algorithm
*
* @param[in/out] ps_cluster_data: pointer to cluster_data_t struct
*
* @param[in/out] pi4_num_clusters : pointer to number of clusters
*
* @param[in] mvx : x co-ordinate of the motion vector
*
* @param[in] mvy : y co-ordinate of the motion vector
*
* @param[in] ref_idx : ref_id of the motion vector
*
* @param[in] e_part_id : partition id of the motion vector
*
* @return None
********************************************************************************
*/
void hme_find_and_update_clusters(
cluster_data_t *ps_cluster_data,
U08 *pu1_num_clusters,
S16 i2_mv_x,
S16 i2_mv_y,
U08 i1_ref_idx,
S32 i4_sdi,
PART_ID_T e_part_id,
U08 is_part_of_bi)
{
S32 i;
S32 min_mvd_cluster_id = -1;
S32 mvd, mvd_limit, mvdx, mvdy;
S32 min_mvdx, min_mvdy;
S32 min_mvd = MAX_32BIT_VAL;
S32 num_clusters = *pu1_num_clusters;
S32 mvx = i2_mv_x;
S32 mvy = i2_mv_y;
S32 ref_idx = i1_ref_idx;
S32 sdi = i4_sdi;
S32 new_cluster_idx = MAX_NUM_CLUSTERS_16x16;
if(num_clusters == 0)
{
cluster_data_t *ps_data = &ps_cluster_data[num_clusters];
ps_data->num_mvs = 1;
ps_data->s_centroid.i4_pos_x_q8 = mvx << 8;
ps_data->s_centroid.i4_pos_y_q8 = mvy << 8;
ps_data->ref_id = ref_idx;
ps_data->area_in_pixels = gai4_partition_area[e_part_id];
ps_data->as_mv[0].pixel_count = gai4_partition_area[e_part_id];
ps_data->as_mv[0].mvx = mvx;
ps_data->as_mv[0].mvy = mvy;
/***************************/
ps_data->as_mv[0].is_uni = !is_part_of_bi;
ps_data->as_mv[0].sdi = sdi;
if(is_part_of_bi)
{
ps_data->bi_mv_pixel_area += ps_data->area_in_pixels;
}
else
{
ps_data->uni_mv_pixel_area += ps_data->area_in_pixels;
}
/**************************/
ps_data->max_x = mvx;
ps_data->min_x = mvx;
ps_data->max_y = mvy;
ps_data->min_y = mvy;
ps_data->is_valid_cluster = 1;
*pu1_num_clusters = 1;
}
else
{
S32 num_clusters_evaluated = 0;
for(i = 0; num_clusters_evaluated < num_clusters; i++)
{
cluster_data_t *ps_data = &ps_cluster_data[i];
centroid_t *ps_centroid;
S32 mvx_q8;
S32 mvy_q8;
S32 posx_q8;
S32 posy_q8;
S32 mvdx_q8;
S32 mvdy_q8;
/* In anticipation of a possible merging of clusters */
if(ps_data->is_valid_cluster == 0)
{
new_cluster_idx = i;
continue;
}
if(ref_idx != ps_data->ref_id)
{
num_clusters_evaluated++;
continue;
}
ps_centroid = &ps_data->s_centroid;
posx_q8 = ps_centroid->i4_pos_x_q8;
posy_q8 = ps_centroid->i4_pos_y_q8;
mvx_q8 = mvx << 8;
mvy_q8 = mvy << 8;
mvdx_q8 = posx_q8 - mvx_q8;
mvdy_q8 = posy_q8 - mvy_q8;
mvdx = (((mvdx_q8 + (1 << 7)) >> 8));
mvdy = (((mvdy_q8 + (1 << 7)) >> 8));
mvd = ABS(mvdx) + ABS(mvdy);
if(mvd < min_mvd)
{
min_mvd = mvd;
min_mvdx = mvdx;
min_mvdy = mvdy;
min_mvd_cluster_id = i;
}
num_clusters_evaluated++;
}
mvd_limit = (min_mvd_cluster_id == -1)
? ps_cluster_data[0].max_dist_from_centroid
: ps_cluster_data[min_mvd_cluster_id].max_dist_from_centroid;
/* This condition implies that min_mvd has been updated */
if(min_mvd <= mvd_limit)
{
hme_update_cluster_attributes(
&ps_cluster_data[min_mvd_cluster_id],
mvx,
mvy,
min_mvdx,
min_mvdy,
ref_idx,
sdi,
is_part_of_bi,
e_part_id);
if(PRT_NxN == ge_part_id_to_part_type[e_part_id])
{
hme_try_cluster_merge(ps_cluster_data, pu1_num_clusters, min_mvd_cluster_id);
}
}
else
{
cluster_data_t *ps_data = (new_cluster_idx == MAX_NUM_CLUSTERS_16x16)
? &ps_cluster_data[num_clusters]
: &ps_cluster_data[new_cluster_idx];
ps_data->num_mvs = 1;
ps_data->s_centroid.i4_pos_x_q8 = mvx << 8;
ps_data->s_centroid.i4_pos_y_q8 = mvy << 8;
ps_data->ref_id = ref_idx;
ps_data->area_in_pixels = gai4_partition_area[e_part_id];
ps_data->as_mv[0].pixel_count = gai4_partition_area[e_part_id];
ps_data->as_mv[0].mvx = mvx;
ps_data->as_mv[0].mvy = mvy;
/***************************/
ps_data->as_mv[0].is_uni = !is_part_of_bi;
ps_data->as_mv[0].sdi = sdi;
if(is_part_of_bi)
{
ps_data->bi_mv_pixel_area += ps_data->area_in_pixels;
}
else
{
ps_data->uni_mv_pixel_area += ps_data->area_in_pixels;
}
/**************************/
ps_data->max_x = mvx;
ps_data->min_x = mvx;
ps_data->max_y = mvy;
ps_data->min_y = mvy;
ps_data->is_valid_cluster = 1;
num_clusters++;
*pu1_num_clusters = num_clusters;
}
}
}
/**
********************************************************************************
* @fn void hme_update_32x32_cluster_attributes
* (
* cluster_32x32_blk_t *ps_blk_32x32,
* cluster_data_t *ps_cluster_data
* )
*
* @brief Updates attributes for 32x32 clusters based on the attributes of
* the constituent 16x16 clusters
*
* @param[out] ps_blk_32x32: structure containing 32x32 block results
*
* @param[in] ps_cluster_data : structure containing 16x16 block results
*
* @return None
********************************************************************************
*/
void hme_update_32x32_cluster_attributes(
cluster_32x32_blk_t *ps_blk_32x32, cluster_data_t *ps_cluster_data)
{
cluster_data_t *ps_cur_cluster_32;
S32 i;
S32 mvd_limit;
S32 num_clusters = ps_blk_32x32->num_clusters;
if(0 == num_clusters)
{
ps_cur_cluster_32 = &ps_blk_32x32->as_cluster_data[0];
ps_blk_32x32->num_clusters++;
ps_blk_32x32->au1_num_clusters[ps_cluster_data->ref_id]++;
ps_cur_cluster_32->is_valid_cluster = 1;
ps_cur_cluster_32->area_in_pixels = ps_cluster_data->area_in_pixels;
ps_cur_cluster_32->bi_mv_pixel_area += ps_cluster_data->bi_mv_pixel_area;
ps_cur_cluster_32->uni_mv_pixel_area += ps_cluster_data->uni_mv_pixel_area;
memcpy(
ps_cur_cluster_32->as_mv,
ps_cluster_data->as_mv,
sizeof(mv_data_t) * ps_cluster_data->num_mvs);
ps_cur_cluster_32->num_mvs = ps_cluster_data->num_mvs;
ps_cur_cluster_32->ref_id = ps_cluster_data->ref_id;
ps_cur_cluster_32->max_x = ps_cluster_data->max_x;
ps_cur_cluster_32->max_y = ps_cluster_data->max_y;
ps_cur_cluster_32->min_x = ps_cluster_data->min_x;
ps_cur_cluster_32->min_y = ps_cluster_data->min_y;
ps_cur_cluster_32->s_centroid = ps_cluster_data->s_centroid;
}
else
{
centroid_t *ps_centroid;
S32 cur_posx_q8, cur_posy_q8;
S32 min_mvd_cluster_id = -1;
S32 mvd;
S32 mvdx;
S32 mvdy;
S32 mvdx_min;
S32 mvdy_min;
S32 mvdx_q8;
S32 mvdy_q8;
S32 num_clusters_evaluated = 0;
S32 mvd_min = MAX_32BIT_VAL;
S32 mvx_inp_q8 = ps_cluster_data->s_centroid.i4_pos_x_q8;
S32 mvy_inp_q8 = ps_cluster_data->s_centroid.i4_pos_y_q8;
for(i = 0; num_clusters_evaluated < num_clusters; i++)
{
ps_cur_cluster_32 = &ps_blk_32x32->as_cluster_data[i];
if(ps_cur_cluster_32->ref_id != ps_cluster_data->ref_id)
{
num_clusters_evaluated++;
continue;
}
if(!ps_cluster_data->is_valid_cluster)
{
continue;
}
num_clusters_evaluated++;
ps_centroid = &ps_cur_cluster_32->s_centroid;
cur_posx_q8 = ps_centroid->i4_pos_x_q8;
cur_posy_q8 = ps_centroid->i4_pos_y_q8;
mvdx_q8 = cur_posx_q8 - mvx_inp_q8;
mvdy_q8 = cur_posy_q8 - mvy_inp_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = ABS(mvdx) + ABS(mvdy);
if(mvd < mvd_min)
{
mvd_min = mvd;
mvdx_min = mvdx;
mvdy_min = mvdy;
min_mvd_cluster_id = i;
}
}
ps_cur_cluster_32 = &ps_blk_32x32->as_cluster_data[0];
mvd_limit = (min_mvd_cluster_id == -1)
? ps_cur_cluster_32[0].max_dist_from_centroid
: ps_cur_cluster_32[min_mvd_cluster_id].max_dist_from_centroid;
if(mvd_min <= mvd_limit)
{
LWORD64 i8_updated_posx;
LWORD64 i8_updated_posy;
WORD32 minmax_updated_x = 0;
WORD32 minmax_updated_y = 0;
ps_cur_cluster_32 = &ps_blk_32x32->as_cluster_data[min_mvd_cluster_id];
ps_centroid = &ps_cur_cluster_32->s_centroid;
ps_cur_cluster_32->is_valid_cluster = 1;
ps_cur_cluster_32->area_in_pixels += ps_cluster_data->area_in_pixels;
ps_cur_cluster_32->bi_mv_pixel_area += ps_cluster_data->bi_mv_pixel_area;
ps_cur_cluster_32->uni_mv_pixel_area += ps_cluster_data->uni_mv_pixel_area;
memcpy(
&ps_cur_cluster_32->as_mv[ps_cur_cluster_32->num_mvs],
ps_cluster_data->as_mv,
sizeof(mv_data_t) * ps_cluster_data->num_mvs);
if((mvdx_min > 0) && ((ps_cur_cluster_32->min_x << 8) > mvx_inp_q8))
{
ps_cur_cluster_32->min_x = (mvx_inp_q8 + ((1 << 7))) >> 8;
minmax_updated_x = 1;
}
else if((mvdx_min < 0) && ((ps_cur_cluster_32->max_x << 8) < mvx_inp_q8))
{
ps_cur_cluster_32->max_x = (mvx_inp_q8 + (1 << 7)) >> 8;
minmax_updated_x = 2;
}
if((mvdy_min > 0) && ((ps_cur_cluster_32->min_y << 8) > mvy_inp_q8))
{
ps_cur_cluster_32->min_y = (mvy_inp_q8 + (1 << 7)) >> 8;
minmax_updated_y = 1;
}
else if((mvdy_min < 0) && ((ps_cur_cluster_32->max_y << 8) < mvy_inp_q8))
{
ps_cur_cluster_32->max_y = (mvy_inp_q8 + (1 << 7)) >> 8;
minmax_updated_y = 2;
}
switch((minmax_updated_y << 2) + minmax_updated_x)
{
case 1:
{
S32 mvd, mvd_q8;
mvd_q8 = ps_centroid->i4_pos_x_q8 - (ps_cur_cluster_32->min_x << 8);
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cur_cluster_32->max_dist_from_centroid = mvd;
}
break;
}
case 2:
{
S32 mvd, mvd_q8;
mvd_q8 = (ps_cur_cluster_32->max_x << 8) - ps_centroid->i4_pos_x_q8;
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cur_cluster_32->max_dist_from_centroid = mvd;
}
break;
}
case 4:
{
S32 mvd, mvd_q8;
mvd_q8 = ps_centroid->i4_pos_y_q8 - (ps_cur_cluster_32->min_y << 8);
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cur_cluster_32->max_dist_from_centroid = mvd;
}
break;
}
case 5:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdy_q8 = ps_centroid->i4_pos_y_q8 - (ps_cur_cluster_32->min_y << 8);
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvdx_q8 = ps_centroid->i4_pos_x_q8 - (ps_cur_cluster_32->min_x << 8);
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > mvd_limit)
{
ps_cur_cluster_32->max_dist_from_centroid = mvd;
}
break;
}
case 6:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdy_q8 = ps_centroid->i4_pos_y_q8 - (ps_cur_cluster_32->min_y << 8);
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvdx_q8 = (ps_cur_cluster_32->max_x << 8) - ps_centroid->i4_pos_x_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > mvd_limit)
{
ps_cur_cluster_32->max_dist_from_centroid = mvd;
}
break;
}
case 8:
{
S32 mvd, mvd_q8;
mvd_q8 = (ps_cur_cluster_32->max_y << 8) - ps_centroid->i4_pos_y_q8;
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cur_cluster_32->max_dist_from_centroid = mvd;
}
break;
}
case 9:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdx_q8 = ps_centroid->i4_pos_x_q8 - (ps_cur_cluster_32->min_x << 8);
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy_q8 = (ps_cur_cluster_32->max_y << 8) - ps_centroid->i4_pos_y_q8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > mvd_limit)
{
ps_cur_cluster_32->max_dist_from_centroid = mvd;
}
break;
}
case 10:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdx_q8 = (ps_cur_cluster_32->max_x << 8) - ps_centroid->i4_pos_x_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy_q8 = (ps_cur_cluster_32->max_y << 8) - ps_centroid->i4_pos_y_q8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > ps_cur_cluster_32->max_dist_from_centroid)
{
ps_cur_cluster_32->max_dist_from_centroid = mvd;
}
break;
}
default:
{
break;
}
}
i8_updated_posx = ((LWORD64)ps_centroid->i4_pos_x_q8 * ps_cur_cluster_32->num_mvs) +
((LWORD64)mvx_inp_q8 * ps_cluster_data->num_mvs);
i8_updated_posy = ((LWORD64)ps_centroid->i4_pos_y_q8 * ps_cur_cluster_32->num_mvs) +
((LWORD64)mvy_inp_q8 * ps_cluster_data->num_mvs);
ps_cur_cluster_32->num_mvs += ps_cluster_data->num_mvs;
ps_centroid->i4_pos_x_q8 = (WORD32)(i8_updated_posx / ps_cur_cluster_32->num_mvs);
ps_centroid->i4_pos_y_q8 = (WORD32)(i8_updated_posy / ps_cur_cluster_32->num_mvs);
}
else if(num_clusters < MAX_NUM_CLUSTERS_32x32)
{
ps_cur_cluster_32 = &ps_blk_32x32->as_cluster_data[num_clusters];
ps_blk_32x32->num_clusters++;
ps_blk_32x32->au1_num_clusters[ps_cluster_data->ref_id]++;
ps_cur_cluster_32->is_valid_cluster = 1;
ps_cur_cluster_32->area_in_pixels = ps_cluster_data->area_in_pixels;
ps_cur_cluster_32->bi_mv_pixel_area += ps_cluster_data->bi_mv_pixel_area;
ps_cur_cluster_32->uni_mv_pixel_area += ps_cluster_data->uni_mv_pixel_area;
memcpy(
ps_cur_cluster_32->as_mv,
ps_cluster_data->as_mv,
sizeof(mv_data_t) * ps_cluster_data->num_mvs);
ps_cur_cluster_32->num_mvs = ps_cluster_data->num_mvs;
ps_cur_cluster_32->ref_id = ps_cluster_data->ref_id;
ps_cur_cluster_32->max_x = ps_cluster_data->max_x;
ps_cur_cluster_32->max_y = ps_cluster_data->max_y;
ps_cur_cluster_32->min_x = ps_cluster_data->min_x;
ps_cur_cluster_32->min_y = ps_cluster_data->min_y;
ps_cur_cluster_32->s_centroid = ps_cluster_data->s_centroid;
}
}
}
/**
********************************************************************************
* @fn void hme_update_64x64_cluster_attributes
* (
* cluster_64x64_blk_t *ps_blk_32x32,
* cluster_data_t *ps_cluster_data
* )
*
* @brief Updates attributes for 64x64 clusters based on the attributes of
* the constituent 16x16 clusters
*
* @param[out] ps_blk_64x64: structure containing 64x64 block results
*
* @param[in] ps_cluster_data : structure containing 32x32 block results
*
* @return None
********************************************************************************
*/
void hme_update_64x64_cluster_attributes(
cluster_64x64_blk_t *ps_blk_64x64, cluster_data_t *ps_cluster_data)
{
cluster_data_t *ps_cur_cluster_64;
S32 i;
S32 mvd_limit;
S32 num_clusters = ps_blk_64x64->num_clusters;
if(0 == num_clusters)
{
ps_cur_cluster_64 = &ps_blk_64x64->as_cluster_data[0];
ps_blk_64x64->num_clusters++;
ps_blk_64x64->au1_num_clusters[ps_cluster_data->ref_id]++;
ps_cur_cluster_64->is_valid_cluster = 1;
ps_cur_cluster_64->area_in_pixels = ps_cluster_data->area_in_pixels;
ps_cur_cluster_64->bi_mv_pixel_area += ps_cluster_data->bi_mv_pixel_area;
ps_cur_cluster_64->uni_mv_pixel_area += ps_cluster_data->uni_mv_pixel_area;
memcpy(
ps_cur_cluster_64->as_mv,
ps_cluster_data->as_mv,
sizeof(mv_data_t) * ps_cluster_data->num_mvs);
ps_cur_cluster_64->num_mvs = ps_cluster_data->num_mvs;
ps_cur_cluster_64->ref_id = ps_cluster_data->ref_id;
ps_cur_cluster_64->max_x = ps_cluster_data->max_x;
ps_cur_cluster_64->max_y = ps_cluster_data->max_y;
ps_cur_cluster_64->min_x = ps_cluster_data->min_x;
ps_cur_cluster_64->min_y = ps_cluster_data->min_y;
ps_cur_cluster_64->s_centroid = ps_cluster_data->s_centroid;
}
else
{
centroid_t *ps_centroid;
S32 cur_posx_q8, cur_posy_q8;
S32 min_mvd_cluster_id = -1;
S32 mvd;
S32 mvdx;
S32 mvdy;
S32 mvdx_min;
S32 mvdy_min;
S32 mvdx_q8;
S32 mvdy_q8;
S32 num_clusters_evaluated = 0;
S32 mvd_min = MAX_32BIT_VAL;
S32 mvx_inp_q8 = ps_cluster_data->s_centroid.i4_pos_x_q8;
S32 mvy_inp_q8 = ps_cluster_data->s_centroid.i4_pos_y_q8;
for(i = 0; num_clusters_evaluated < num_clusters; i++)
{
ps_cur_cluster_64 = &ps_blk_64x64->as_cluster_data[i];
if(ps_cur_cluster_64->ref_id != ps_cluster_data->ref_id)
{
num_clusters_evaluated++;
continue;
}
if(!ps_cur_cluster_64->is_valid_cluster)
{
continue;
}
num_clusters_evaluated++;
ps_centroid = &ps_cur_cluster_64->s_centroid;
cur_posx_q8 = ps_centroid->i4_pos_x_q8;
cur_posy_q8 = ps_centroid->i4_pos_y_q8;
mvdx_q8 = cur_posx_q8 - mvx_inp_q8;
mvdy_q8 = cur_posy_q8 - mvy_inp_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = ABS(mvdx) + ABS(mvdy);
if(mvd < mvd_min)
{
mvd_min = mvd;
mvdx_min = mvdx;
mvdy_min = mvdy;
min_mvd_cluster_id = i;
}
}
ps_cur_cluster_64 = ps_blk_64x64->as_cluster_data;
mvd_limit = (min_mvd_cluster_id == -1)
? ps_cur_cluster_64[0].max_dist_from_centroid
: ps_cur_cluster_64[min_mvd_cluster_id].max_dist_from_centroid;
if(mvd_min <= mvd_limit)
{
LWORD64 i8_updated_posx;
LWORD64 i8_updated_posy;
WORD32 minmax_updated_x = 0;
WORD32 minmax_updated_y = 0;
ps_cur_cluster_64 = &ps_blk_64x64->as_cluster_data[min_mvd_cluster_id];
ps_centroid = &ps_cur_cluster_64->s_centroid;
ps_cur_cluster_64->is_valid_cluster = 1;
ps_cur_cluster_64->area_in_pixels += ps_cluster_data->area_in_pixels;
ps_cur_cluster_64->bi_mv_pixel_area += ps_cluster_data->bi_mv_pixel_area;
ps_cur_cluster_64->uni_mv_pixel_area += ps_cluster_data->uni_mv_pixel_area;
memcpy(
&ps_cur_cluster_64->as_mv[ps_cur_cluster_64->num_mvs],
ps_cluster_data->as_mv,
sizeof(mv_data_t) * ps_cluster_data->num_mvs);
if((mvdx_min > 0) && ((ps_cur_cluster_64->min_x << 8) > mvx_inp_q8))
{
ps_cur_cluster_64->min_x = (mvx_inp_q8 + (1 << 7)) >> 8;
minmax_updated_x = 1;
}
else if((mvdx_min < 0) && ((ps_cur_cluster_64->max_x << 8) < mvx_inp_q8))
{
ps_cur_cluster_64->max_x = (mvx_inp_q8 + (1 << 7)) >> 8;
minmax_updated_x = 2;
}
if((mvdy_min > 0) && ((ps_cur_cluster_64->min_y << 8) > mvy_inp_q8))
{
ps_cur_cluster_64->min_y = (mvy_inp_q8 + (1 << 7)) >> 8;
minmax_updated_y = 1;
}
else if((mvdy_min < 0) && ((ps_cur_cluster_64->max_y << 8) < mvy_inp_q8))
{
ps_cur_cluster_64->max_y = (mvy_inp_q8 + (1 << 7)) >> 8;
minmax_updated_y = 2;
}
switch((minmax_updated_y << 2) + minmax_updated_x)
{
case 1:
{
S32 mvd, mvd_q8;
mvd_q8 = ps_centroid->i4_pos_x_q8 - (ps_cur_cluster_64->min_x << 8);
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cur_cluster_64->max_dist_from_centroid = mvd;
}
break;
}
case 2:
{
S32 mvd, mvd_q8;
mvd_q8 = (ps_cur_cluster_64->max_x << 8) - ps_centroid->i4_pos_x_q8;
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cur_cluster_64->max_dist_from_centroid = mvd;
}
break;
}
case 4:
{
S32 mvd, mvd_q8;
mvd_q8 = ps_centroid->i4_pos_y_q8 - (ps_cur_cluster_64->min_y << 8);
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cur_cluster_64->max_dist_from_centroid = mvd;
}
break;
}
case 5:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdy_q8 = ps_centroid->i4_pos_y_q8 - (ps_cur_cluster_64->min_y << 8);
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvdx_q8 = ps_centroid->i4_pos_x_q8 - (ps_cur_cluster_64->min_x << 8);
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > mvd_limit)
{
ps_cur_cluster_64->max_dist_from_centroid = mvd;
}
break;
}
case 6:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdy_q8 = ps_centroid->i4_pos_y_q8 - (ps_cur_cluster_64->min_y << 8);
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvdx_q8 = (ps_cur_cluster_64->max_x << 8) - ps_centroid->i4_pos_x_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > mvd_limit)
{
ps_cur_cluster_64->max_dist_from_centroid = mvd;
}
break;
}
case 8:
{
S32 mvd, mvd_q8;
mvd_q8 = (ps_cur_cluster_64->max_y << 8) - ps_centroid->i4_pos_y_q8;
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cur_cluster_64->max_dist_from_centroid = mvd;
}
break;
}
case 9:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdx_q8 = ps_centroid->i4_pos_x_q8 - (ps_cur_cluster_64->min_x << 8);
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy_q8 = (ps_cur_cluster_64->max_y << 8) - ps_centroid->i4_pos_y_q8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > mvd_limit)
{
ps_cur_cluster_64->max_dist_from_centroid = mvd;
}
break;
}
case 10:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdx_q8 = (ps_cur_cluster_64->max_x << 8) - ps_centroid->i4_pos_x_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy_q8 = (ps_cur_cluster_64->max_y << 8) - ps_centroid->i4_pos_y_q8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > ps_cur_cluster_64->max_dist_from_centroid)
{
ps_cur_cluster_64->max_dist_from_centroid = mvd;
}
break;
}
default:
{
break;
}
}
i8_updated_posx = ((LWORD64)ps_centroid->i4_pos_x_q8 * ps_cur_cluster_64->num_mvs) +
((LWORD64)mvx_inp_q8 * ps_cluster_data->num_mvs);
i8_updated_posy = ((LWORD64)ps_centroid->i4_pos_y_q8 * ps_cur_cluster_64->num_mvs) +
((LWORD64)mvy_inp_q8 * ps_cluster_data->num_mvs);
ps_cur_cluster_64->num_mvs += ps_cluster_data->num_mvs;
ps_centroid->i4_pos_x_q8 = (WORD32)(i8_updated_posx / ps_cur_cluster_64->num_mvs);
ps_centroid->i4_pos_y_q8 = (WORD32)(i8_updated_posy / ps_cur_cluster_64->num_mvs);
}
else if(num_clusters < MAX_NUM_CLUSTERS_64x64)
{
ps_cur_cluster_64 = &ps_blk_64x64->as_cluster_data[num_clusters];
ps_blk_64x64->num_clusters++;
ps_blk_64x64->au1_num_clusters[ps_cluster_data->ref_id]++;
ps_cur_cluster_64->is_valid_cluster = 1;
ps_cur_cluster_64->area_in_pixels = ps_cluster_data->area_in_pixels;
ps_cur_cluster_64->bi_mv_pixel_area += ps_cluster_data->bi_mv_pixel_area;
ps_cur_cluster_64->uni_mv_pixel_area += ps_cluster_data->uni_mv_pixel_area;
memcpy(
&ps_cur_cluster_64->as_mv[0],
ps_cluster_data->as_mv,
sizeof(mv_data_t) * ps_cluster_data->num_mvs);
ps_cur_cluster_64->num_mvs = ps_cluster_data->num_mvs;
ps_cur_cluster_64->ref_id = ps_cluster_data->ref_id;
ps_cur_cluster_64->max_x = ps_cluster_data->max_x;
ps_cur_cluster_64->max_y = ps_cluster_data->max_y;
ps_cur_cluster_64->min_x = ps_cluster_data->min_x;
ps_cur_cluster_64->min_y = ps_cluster_data->min_y;
ps_cur_cluster_64->s_centroid = ps_cluster_data->s_centroid;
}
}
}
/**
********************************************************************************
* @fn void hme_update_32x32_clusters
* (
* cluster_32x32_blk_t *ps_blk_32x32,
* cluster_16x16_blk_t *ps_blk_16x16
* )
*
* @brief Updates attributes for 32x32 clusters based on the attributes of
* the constituent 16x16 clusters
*
* @param[out] ps_blk_32x32: structure containing 32x32 block results
*
* @param[in] ps_blk_16x16 : structure containing 16x16 block results
*
* @return None
********************************************************************************
*/
static __inline void
hme_update_32x32_clusters(cluster_32x32_blk_t *ps_blk_32x32, cluster_16x16_blk_t *ps_blk_16x16)
{
cluster_16x16_blk_t *ps_blk_16x16_cur;
cluster_data_t *ps_cur_cluster;
S32 i, j;
S32 num_clusters_cur_16x16_blk;
for(i = 0; i < 4; i++)
{
S32 num_clusters_evaluated = 0;
ps_blk_16x16_cur = &ps_blk_16x16[i];
num_clusters_cur_16x16_blk = ps_blk_16x16_cur->num_clusters;
ps_blk_32x32->intra_mv_area += ps_blk_16x16_cur->intra_mv_area;
ps_blk_32x32->best_inter_cost += ps_blk_16x16_cur->best_inter_cost;
for(j = 0; num_clusters_evaluated < num_clusters_cur_16x16_blk; j++)
{
ps_cur_cluster = &ps_blk_16x16_cur->as_cluster_data[j];
if(!ps_cur_cluster->is_valid_cluster)
{
continue;
}
hme_update_32x32_cluster_attributes(ps_blk_32x32, ps_cur_cluster);
num_clusters_evaluated++;
}
}
}
/**
********************************************************************************
* @fn void hme_update_64x64_clusters
* (
* cluster_64x64_blk_t *ps_blk_64x64,
* cluster_32x32_blk_t *ps_blk_32x32
* )
*
* @brief Updates attributes for 64x64 clusters based on the attributes of
* the constituent 16x16 clusters
*
* @param[out] ps_blk_64x64: structure containing 32x32 block results
*
* @param[in] ps_blk_32x32 : structure containing 16x16 block results
*
* @return None
********************************************************************************
*/
static __inline void
hme_update_64x64_clusters(cluster_64x64_blk_t *ps_blk_64x64, cluster_32x32_blk_t *ps_blk_32x32)
{
cluster_32x32_blk_t *ps_blk_32x32_cur;
cluster_data_t *ps_cur_cluster;
S32 i, j;
S32 num_clusters_cur_32x32_blk;
for(i = 0; i < 4; i++)
{
S32 num_clusters_evaluated = 0;
ps_blk_32x32_cur = &ps_blk_32x32[i];
num_clusters_cur_32x32_blk = ps_blk_32x32_cur->num_clusters;
ps_blk_64x64->intra_mv_area += ps_blk_32x32_cur->intra_mv_area;
ps_blk_64x64->best_inter_cost += ps_blk_32x32_cur->best_inter_cost;
for(j = 0; num_clusters_evaluated < num_clusters_cur_32x32_blk; j++)
{
ps_cur_cluster = &ps_blk_32x32_cur->as_cluster_data[j];
if(!ps_cur_cluster->is_valid_cluster)
{
continue;
}
hme_update_64x64_cluster_attributes(ps_blk_64x64, ps_cur_cluster);
num_clusters_evaluated++;
}
}
}
/**
********************************************************************************
* @fn void hme_try_merge_clusters_blksize_gt_16
* (
* cluster_data_t *ps_cluster_data,
* S32 num_clusters
* )
*
* @brief Merging clusters from blocks of size 32x32 and greater
*
* @param[in/out] ps_cluster_data: structure containing cluster data
*
* @param[in/out] pi4_num_clusters : pointer to number of clusters
*
* @return Success or failure
********************************************************************************
*/
S32 hme_try_merge_clusters_blksize_gt_16(cluster_data_t *ps_cluster_data, S32 num_clusters)
{
centroid_t *ps_cur_centroid;
cluster_data_t *ps_cur_cluster;
S32 i, mvd;
S32 mvdx, mvdy, mvdx_q8, mvdy_q8;
centroid_t *ps_centroid = &ps_cluster_data->s_centroid;
S32 mvd_limit = ps_cluster_data->max_dist_from_centroid;
S32 ref_id = ps_cluster_data->ref_id;
S32 node0_posx_q8 = ps_centroid->i4_pos_x_q8;
S32 node0_posy_q8 = ps_centroid->i4_pos_y_q8;
S32 num_clusters_evaluated = 1;
S32 ret_value = 0;
if(1 >= num_clusters)
{
return ret_value;
}
for(i = 1; num_clusters_evaluated < num_clusters; i++)
{
S32 cur_posx_q8;
S32 cur_posy_q8;
ps_cur_cluster = &ps_cluster_data[i];
if((ref_id != ps_cur_cluster->ref_id))
{
num_clusters_evaluated++;
continue;
}
if((!ps_cur_cluster->is_valid_cluster))
{
continue;
}
num_clusters_evaluated++;
ps_cur_centroid = &ps_cur_cluster->s_centroid;
cur_posx_q8 = ps_cur_centroid->i4_pos_x_q8;
cur_posy_q8 = ps_cur_centroid->i4_pos_y_q8;
mvdx_q8 = cur_posx_q8 - node0_posx_q8;
mvdy_q8 = cur_posy_q8 - node0_posy_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = ABS(mvdx) + ABS(mvdy);
if(mvd <= (mvd_limit >> 1))
{
LWORD64 i8_updated_posx;
LWORD64 i8_updated_posy;
WORD32 minmax_updated_x = 0;
WORD32 minmax_updated_y = 0;
ps_cur_cluster->is_valid_cluster = 0;
ps_cluster_data->area_in_pixels += ps_cur_cluster->area_in_pixels;
ps_cluster_data->bi_mv_pixel_area += ps_cur_cluster->bi_mv_pixel_area;
ps_cluster_data->uni_mv_pixel_area += ps_cur_cluster->uni_mv_pixel_area;
memcpy(
&ps_cluster_data->as_mv[ps_cluster_data->num_mvs],
ps_cur_cluster->as_mv,
sizeof(mv_data_t) * ps_cur_cluster->num_mvs);
if(mvdx > 0)
{
ps_cluster_data->min_x = (cur_posx_q8 + (1 << 7)) >> 8;
minmax_updated_x = 1;
}
else
{
ps_cluster_data->max_x = (cur_posx_q8 + (1 << 7)) >> 8;
minmax_updated_x = 2;
}
if(mvdy > 0)
{
ps_cluster_data->min_y = (cur_posy_q8 + (1 << 7)) >> 8;
minmax_updated_y = 1;
}
else
{
ps_cluster_data->max_y = (cur_posy_q8 + (1 << 7)) >> 8;
minmax_updated_y = 2;
}
switch((minmax_updated_y << 2) + minmax_updated_x)
{
case 1:
{
S32 mvd, mvd_q8;
mvd_q8 = ps_cur_centroid->i4_pos_x_q8 - (ps_cluster_data->min_x << 8);
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 2:
{
S32 mvd, mvd_q8;
mvd_q8 = (ps_cluster_data->max_x << 8) - ps_cur_centroid->i4_pos_x_q8;
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 4:
{
S32 mvd, mvd_q8;
mvd_q8 = ps_cur_centroid->i4_pos_y_q8 - (ps_cluster_data->min_y << 8);
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 5:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdy_q8 = ps_cur_centroid->i4_pos_y_q8 - (ps_cluster_data->min_y << 8);
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvdx_q8 = ps_cur_centroid->i4_pos_x_q8 - (ps_cluster_data->min_x << 8);
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > mvd_limit)
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 6:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdy_q8 = ps_cur_centroid->i4_pos_y_q8 - (ps_cluster_data->min_y << 8);
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvdx_q8 = (ps_cluster_data->max_x << 8) - ps_cur_centroid->i4_pos_x_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > mvd_limit)
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 8:
{
S32 mvd, mvd_q8;
mvd_q8 = (ps_cluster_data->max_y << 8) - ps_cur_centroid->i4_pos_y_q8;
mvd = (mvd_q8 + (1 << 7)) >> 8;
if(mvd > (mvd_limit))
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 9:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdx_q8 = ps_cur_centroid->i4_pos_x_q8 - (ps_cluster_data->min_x << 8);
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy_q8 = (ps_cluster_data->max_y << 8) - ps_cur_centroid->i4_pos_y_q8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > mvd_limit)
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
case 10:
{
S32 mvd;
S32 mvdx, mvdx_q8;
S32 mvdy, mvdy_q8;
mvdx_q8 = (ps_cluster_data->max_x << 8) - ps_cur_centroid->i4_pos_x_q8;
mvdx = (mvdx_q8 + (1 << 7)) >> 8;
mvdy_q8 = (ps_cluster_data->max_y << 8) - ps_cur_centroid->i4_pos_y_q8;
mvdy = (mvdy_q8 + (1 << 7)) >> 8;
mvd = (mvdx > mvdy) ? mvdx : mvdy;
if(mvd > ps_cluster_data->max_dist_from_centroid)
{
ps_cluster_data->max_dist_from_centroid = mvd;
}
break;
}
default:
{
break;
}
}
i8_updated_posx = ((LWORD64)ps_centroid->i4_pos_x_q8 * ps_cluster_data->num_mvs) +
((LWORD64)cur_posx_q8 * ps_cur_cluster->num_mvs);
i8_updated_posy = ((LWORD64)ps_centroid->i4_pos_y_q8 * ps_cluster_data->num_mvs) +
((LWORD64)cur_posy_q8 * ps_cur_cluster->num_mvs);
ps_cluster_data->num_mvs += ps_cur_cluster->num_mvs;
ps_centroid->i4_pos_x_q8 = (WORD32)(i8_updated_posx / ps_cluster_data->num_mvs);
ps_centroid->i4_pos_y_q8 = (WORD32)(i8_updated_posy / ps_cluster_data->num_mvs);
if(MAX_NUM_CLUSTERS_IN_VALID_64x64_BLK >= num_clusters)
{
num_clusters--;
num_clusters_evaluated = 1;
i = 0;
ret_value++;
}
else
{
ret_value++;
return ret_value;
}
}
}
if(ret_value)
{
for(i = 1; i < (num_clusters + ret_value); i++)
{
if(ps_cluster_data[i].is_valid_cluster)
{
break;
}
}
if(i == (num_clusters + ret_value))
{
return ret_value;
}
}
else
{
i = 1;
}
return (hme_try_merge_clusters_blksize_gt_16(&ps_cluster_data[i], num_clusters - 1)) +
ret_value;
}
/**
********************************************************************************
* @fn S32 hme_determine_validity_32x32
* (
* ctb_cluster_info_t *ps_ctb_cluster_info
* )
*
* @brief Determines whther current 32x32 block needs to be evaluated in enc_loop
* while recursing through the CU tree or not
*
* @param[in] ps_cluster_data: structure containing cluster data
*
* @return Success or failure
********************************************************************************
*/
__inline S32 hme_determine_validity_32x32(
ctb_cluster_info_t *ps_ctb_cluster_info,
S32 *pi4_children_nodes_required,
S32 blk_validity_wrt_pic_bndry,
S32 parent_blk_validity_wrt_pic_bndry)
{
cluster_data_t *ps_data;
cluster_32x32_blk_t *ps_32x32_blk = ps_ctb_cluster_info->ps_32x32_blk;
cluster_64x64_blk_t *ps_64x64_blk = ps_ctb_cluster_info->ps_64x64_blk;
S32 num_clusters = ps_32x32_blk->num_clusters;
S32 num_clusters_parent = ps_64x64_blk->num_clusters;
if(!blk_validity_wrt_pic_bndry)
{
*pi4_children_nodes_required = 1;
return 0;
}
if(!parent_blk_validity_wrt_pic_bndry)
{
*pi4_children_nodes_required = 1;
return 1;
}
if(num_clusters > MAX_NUM_CLUSTERS_IN_VALID_32x32_BLK)
{
*pi4_children_nodes_required = 1;
return 0;
}
if(num_clusters_parent > MAX_NUM_CLUSTERS_IN_VALID_64x64_BLK)
{
*pi4_children_nodes_required = 1;
return 1;
}
else if(num_clusters_parent < MAX_NUM_CLUSTERS_IN_VALID_64x64_BLK)
{
*pi4_children_nodes_required = 0;
return 1;
}
else
{
if(num_clusters < MAX_NUM_CLUSTERS_IN_VALID_32x32_BLK)
{
*pi4_children_nodes_required = 0;
return 1;
}
else
{
S32 i;
S32 area_of_parent = gai4_partition_area[PART_ID_2Nx2N] << 4;
S32 min_area = MAX_32BIT_VAL;
S32 num_clusters_evaluated = 0;
for(i = 0; num_clusters_evaluated < num_clusters; i++)
{
ps_data = &ps_32x32_blk->as_cluster_data[i];
if(!ps_data->is_valid_cluster)
{
continue;
}
num_clusters_evaluated++;
if(ps_data->area_in_pixels < min_area)
{
min_area = ps_data->area_in_pixels;
}
}
if((min_area << 4) < area_of_parent)
{
*pi4_children_nodes_required = 1;
return 0;
}
else
{
*pi4_children_nodes_required = 0;
return 1;
}
}
}
}
/**
********************************************************************************
* @fn S32 hme_determine_validity_16x16
* (
* ctb_cluster_info_t *ps_ctb_cluster_info
* )
*
* @brief Determines whther current 16x16 block needs to be evaluated in enc_loop
* while recursing through the CU tree or not
*
* @param[in] ps_cluster_data: structure containing cluster data
*
* @return Success or failure
********************************************************************************
*/
__inline S32 hme_determine_validity_16x16(
ctb_cluster_info_t *ps_ctb_cluster_info,
S32 *pi4_children_nodes_required,
S32 blk_validity_wrt_pic_bndry,
S32 parent_blk_validity_wrt_pic_bndry)
{
cluster_data_t *ps_data;
cluster_16x16_blk_t *ps_16x16_blk = ps_ctb_cluster_info->ps_16x16_blk;
cluster_32x32_blk_t *ps_32x32_blk = ps_ctb_cluster_info->ps_32x32_blk;
cluster_64x64_blk_t *ps_64x64_blk = ps_ctb_cluster_info->ps_64x64_blk;
S32 num_clusters = ps_16x16_blk->num_clusters;
S32 num_clusters_parent = ps_32x32_blk->num_clusters;
S32 num_clusters_grandparent = ps_64x64_blk->num_clusters;
if(!blk_validity_wrt_pic_bndry)
{
*pi4_children_nodes_required = 1;
return 0;
}
if(!parent_blk_validity_wrt_pic_bndry)
{
*pi4_children_nodes_required = 1;
return 1;
}
if((num_clusters_parent > MAX_NUM_CLUSTERS_IN_VALID_32x32_BLK) &&
(num_clusters_grandparent > MAX_NUM_CLUSTERS_IN_VALID_64x64_BLK))
{
*pi4_children_nodes_required = 1;
return 1;
}
/* Implies nc_64 <= 3 when num_clusters_parent > 3 & */
/* implies nc_64 > 3 when num_clusters_parent < 3 & */
if(num_clusters_parent != MAX_NUM_CLUSTERS_IN_VALID_32x32_BLK)
{
if(num_clusters <= MAX_NUM_CLUSTERS_IN_VALID_16x16_BLK)
{
*pi4_children_nodes_required = 0;
return 1;
}
else
{
*pi4_children_nodes_required = 1;
return 0;
}
}
/* Implies nc_64 >= 3 */
else
{
if(num_clusters < MAX_NUM_CLUSTERS_IN_VALID_16x16_BLK)
{
*pi4_children_nodes_required = 0;
return 1;
}
else if(num_clusters > MAX_NUM_CLUSTERS_IN_VALID_16x16_BLK)
{
*pi4_children_nodes_required = 1;
return 0;
}
else
{
S32 i;
S32 area_of_parent = gai4_partition_area[PART_ID_2Nx2N] << 2;
S32 min_area = MAX_32BIT_VAL;
S32 num_clusters_evaluated = 0;
for(i = 0; num_clusters_evaluated < num_clusters; i++)
{
ps_data = &ps_16x16_blk->as_cluster_data[i];
if(!ps_data->is_valid_cluster)
{
continue;
}
num_clusters_evaluated++;
if(ps_data->area_in_pixels < min_area)
{
min_area = ps_data->area_in_pixels;
}
}
if((min_area << 4) < area_of_parent)
{
*pi4_children_nodes_required = 1;
return 0;
}
else
{
*pi4_children_nodes_required = 0;
return 1;
}
}
}
}
/**
********************************************************************************
* @fn void hme_build_cu_tree
* (
* ctb_cluster_info_t *ps_ctb_cluster_info,
* cur_ctb_cu_tree_t *ps_cu_tree,
* S32 tree_depth,
* CU_POS_T e_grand_parent_blk_pos,
* CU_POS_T e_parent_blk_pos,
* CU_POS_T e_cur_blk_pos
* )
*
* @brief Recursive function for CU tree initialisation
*
* @param[in] ps_ctb_cluster_info: structure containing pointers to clusters
* corresponding to all block sizes from 64x64
* to 16x16
*
* @param[in] e_parent_blk_pos: position of parent block wrt its parent, if
* applicable
*
* @param[in] e_cur_blk_pos: position of current block wrt parent
*
* @param[out] ps_cu_tree : represents CU tree used in CU recursion
*
* @param[in] tree_depth : specifies depth of the CU tree
*
* @return Nothing
********************************************************************************
*/
void hme_build_cu_tree(
ctb_cluster_info_t *ps_ctb_cluster_info,
cur_ctb_cu_tree_t *ps_cu_tree,
S32 tree_depth,
CU_POS_T e_grandparent_blk_pos,
CU_POS_T e_parent_blk_pos,
CU_POS_T e_cur_blk_pos)
{
ihevce_cu_tree_init(
ps_cu_tree,
ps_ctb_cluster_info->ps_cu_tree_root,
&ps_ctb_cluster_info->nodes_created_in_cu_tree,
tree_depth,
e_grandparent_blk_pos,
e_parent_blk_pos,
e_cur_blk_pos);
}
/**
********************************************************************************
* @fn S32 hme_sdi_based_cluster_spread_eligibility
* (
* cluster_32x32_blk_t *ps_blk_32x32
* )
*
* @brief Determines whether the spread of high SDI MV's around each cluster
* center is below a pre-determined threshold
*
* @param[in] ps_blk_32x32: structure containing pointers to clusters
* corresponding to all block sizes from 64x64
* to 16x16
*
* @return 1 if the spread is constrained, else 0
********************************************************************************
*/
__inline S32
hme_sdi_based_cluster_spread_eligibility(cluster_32x32_blk_t *ps_blk_32x32, S32 sdi_threshold)
{
S32 cumulative_mv_distance;
S32 i, j;
S32 num_high_sdi_mvs;
S32 num_clusters = ps_blk_32x32->num_clusters;
for(i = 0; i < num_clusters; i++)
{
cluster_data_t *ps_data = &ps_blk_32x32->as_cluster_data[i];
num_high_sdi_mvs = 0;
cumulative_mv_distance = 0;
for(j = 0; j < ps_data->num_mvs; j++)
{
mv_data_t *ps_mv = &ps_data->as_mv[j];
if(ps_mv->sdi >= sdi_threshold)
{
num_high_sdi_mvs++;
COMPUTE_MVD(ps_mv, ps_data, cumulative_mv_distance);
}
}
if(cumulative_mv_distance > ((ps_data->max_dist_from_centroid >> 1) * num_high_sdi_mvs))
{
return 0;
}
}
return 1;
}
/**
********************************************************************************
* @fn S32 hme_populate_cu_tree
* (
* ctb_cluster_info_t *ps_ctb_cluster_info,
* ipe_l0_ctb_analyse_for_me_t *ps_cur_ipe_ctb,
* cur_ctb_cu_tree_t *ps_cu_tree,
* S32 tree_depth,
* CU_POS_T e_parent_blk_pos,
* CU_POS_T e_cur_blk_pos
* )
*
* @brief Recursive function for CU tree population based on output of
* clustering algorithm
*
* @param[in] ps_ctb_cluster_info: structure containing pointers to clusters
* corresponding to all block sizes from 64x64
* to 16x16
*
* @param[in] e_parent_blk_pos: position of parent block wrt its parent, if
applicable
*
* @param[in] e_cur_blk_pos: position of current block wrt parent
*
* @param[in] ps_cur_ipe_ctb : output container for ipe analyses
*
* @param[out] ps_cu_tree : represents CU tree used in CU recursion
*
* @param[in] tree_depth : specifies depth of the CU tree
*
* @param[in] ipe_decision_precedence : specifies whether precedence should
* be given to decisions made either by IPE(1) or clustering algos.
*
* @return 1 if re-evaluation of parent node's validity is not required,
else 0
********************************************************************************
*/
void hme_populate_cu_tree(
ctb_cluster_info_t *ps_ctb_cluster_info,
cur_ctb_cu_tree_t *ps_cu_tree,
S32 tree_depth,
ME_QUALITY_PRESETS_T e_quality_preset,
CU_POS_T e_grandparent_blk_pos,
CU_POS_T e_parent_blk_pos,
CU_POS_T e_cur_blk_pos)
{
S32 area_of_cur_blk;
S32 area_limit_for_me_decision_precedence;
S32 children_nodes_required;
S32 intra_mv_area;
S32 intra_eval_enable;
S32 inter_eval_enable;
S32 ipe_decision_precedence;
S32 node_validity;
S32 num_clusters;
ipe_l0_ctb_analyse_for_me_t *ps_cur_ipe_ctb = ps_ctb_cluster_info->ps_cur_ipe_ctb;
if(NULL == ps_cu_tree)
{
return;
}
switch(tree_depth)
{
case 0:
{
/* 64x64 block */
S32 blk_32x32_mask = ps_ctb_cluster_info->blk_32x32_mask;
cluster_64x64_blk_t *ps_blk_64x64 = ps_ctb_cluster_info->ps_64x64_blk;
area_of_cur_blk = gai4_partition_area[PART_ID_2Nx2N] << 4;
area_limit_for_me_decision_precedence = (area_of_cur_blk * MAX_INTRA_PERCENTAGE) / 100;
children_nodes_required = 0;
intra_mv_area = ps_blk_64x64->intra_mv_area;
ipe_decision_precedence = (intra_mv_area >= area_limit_for_me_decision_precedence);
intra_eval_enable = ipe_decision_precedence;
inter_eval_enable = !!ps_blk_64x64->num_clusters;
#if 1 //!PROCESS_GT_1CTB_VIA_CU_RECUR_IN_FAST_PRESETS
if(e_quality_preset >= ME_HIGH_QUALITY)
{
inter_eval_enable = 1;
node_validity = (blk_32x32_mask == 0xf);
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
ps_cu_tree->u1_inter_eval_enable = !(intra_mv_area == area_of_cur_blk);
#endif
break;
}
#endif
#if ENABLE_4CTB_EVALUATION
node_validity = (blk_32x32_mask == 0xf);
break;
#else
{
S32 i;
num_clusters = ps_blk_64x64->num_clusters;
node_validity = (ipe_decision_precedence)
? (!ps_cur_ipe_ctb->u1_split_flag)
: (num_clusters <= MAX_NUM_CLUSTERS_IN_VALID_64x64_BLK);
for(i = 0; i < MAX_NUM_REF; i++)
{
node_validity = node_validity && (ps_blk_64x64->au1_num_clusters[i] <=
MAX_NUM_CLUSTERS_IN_ONE_REF_IDX);
}
node_validity = node_validity && (blk_32x32_mask == 0xf);
}
break;
#endif
}
case 1:
{
/* 32x32 block */
S32 is_percent_intra_area_gt_threshold;
cluster_32x32_blk_t *ps_blk_32x32 = &ps_ctb_cluster_info->ps_32x32_blk[e_cur_blk_pos];
S32 blk_32x32_mask = ps_ctb_cluster_info->blk_32x32_mask;
#if !ENABLE_4CTB_EVALUATION
S32 best_inter_cost = ps_blk_32x32->best_inter_cost;
S32 best_intra_cost =
((ps_ctb_cluster_info->ps_cur_ipe_ctb->ai4_best32x32_intra_cost[e_cur_blk_pos] +
ps_ctb_cluster_info->i4_frame_qstep * ps_ctb_cluster_info->i4_frame_qstep_multiplier *
4) < 0)
? MAX_32BIT_VAL
: (ps_ctb_cluster_info->ps_cur_ipe_ctb->ai4_best32x32_intra_cost[e_cur_blk_pos] +
ps_ctb_cluster_info->i4_frame_qstep *
ps_ctb_cluster_info->i4_frame_qstep_multiplier * 4);
S32 best_cost = (best_inter_cost > best_intra_cost) ? best_intra_cost : best_inter_cost;
S32 cost_differential = (best_inter_cost - best_cost);
#endif
area_of_cur_blk = gai4_partition_area[PART_ID_2Nx2N] << 2;
area_limit_for_me_decision_precedence = (area_of_cur_blk * MAX_INTRA_PERCENTAGE) / 100;
intra_mv_area = ps_blk_32x32->intra_mv_area;
is_percent_intra_area_gt_threshold =
(intra_mv_area > area_limit_for_me_decision_precedence);
ipe_decision_precedence = (intra_mv_area >= area_limit_for_me_decision_precedence);
intra_eval_enable = ipe_decision_precedence;
inter_eval_enable = !!ps_blk_32x32->num_clusters;
children_nodes_required = 1;
#if 1 //!PROCESS_GT_1CTB_VIA_CU_RECUR_IN_FAST_PRESETS
if(e_quality_preset >= ME_HIGH_QUALITY)
{
inter_eval_enable = 1;
node_validity = (((blk_32x32_mask) & (1 << e_cur_blk_pos)) || 0);
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
ps_cu_tree->u1_inter_eval_enable = !(intra_mv_area == area_of_cur_blk);
#endif
break;
}
#endif
#if ENABLE_4CTB_EVALUATION
node_validity = (((blk_32x32_mask) & (1 << e_cur_blk_pos)) || 0);
break;
#else
{
S32 i;
num_clusters = ps_blk_32x32->num_clusters;
if(ipe_decision_precedence)
{
node_validity = (ps_cur_ipe_ctb->as_intra32_analyse[e_cur_blk_pos].b1_merge_flag);
node_validity = node_validity && (((blk_32x32_mask) & (1 << e_cur_blk_pos)) || 0);
}
else
{
node_validity =
((ALL_INTER_COST_DIFF_THR * best_cost) >= (100 * cost_differential)) &&
(num_clusters <= MAX_NUM_CLUSTERS_IN_VALID_32x32_BLK) &&
(((blk_32x32_mask) & (1 << e_cur_blk_pos)) || 0);
for(i = 0; (i < MAX_NUM_REF) && (node_validity); i++)
{
node_validity = node_validity && (ps_blk_32x32->au1_num_clusters[i] <=
MAX_NUM_CLUSTERS_IN_ONE_REF_IDX);
}
if(node_validity)
{
node_validity = node_validity &&
hme_sdi_based_cluster_spread_eligibility(
ps_blk_32x32, ps_ctb_cluster_info->sdi_threshold);
}
}
}
break;
#endif
}
case 2:
{
cluster_16x16_blk_t *ps_blk_16x16 =
&ps_ctb_cluster_info->ps_16x16_blk[e_cur_blk_pos + (e_parent_blk_pos << 2)];
S32 blk_8x8_mask =
ps_ctb_cluster_info->pi4_blk_8x8_mask[(S32)(e_parent_blk_pos << 2) + e_cur_blk_pos];
area_of_cur_blk = gai4_partition_area[PART_ID_2Nx2N];
area_limit_for_me_decision_precedence = (area_of_cur_blk * MAX_INTRA_PERCENTAGE) / 100;
children_nodes_required = 1;
intra_mv_area = ps_blk_16x16->intra_mv_area;
ipe_decision_precedence = (intra_mv_area >= area_limit_for_me_decision_precedence);
num_clusters = ps_blk_16x16->num_clusters;
intra_eval_enable = ipe_decision_precedence;
inter_eval_enable = 1;
#if 1 //!PROCESS_GT_1CTB_VIA_CU_RECUR_IN_FAST_PRESETS
if(e_quality_preset >= ME_HIGH_QUALITY)
{
node_validity =
!ps_ctb_cluster_info
->au1_is_16x16_blk_split[(S32)(e_parent_blk_pos << 2) + e_cur_blk_pos];
children_nodes_required = !node_validity;
break;
}
#endif
#if ENABLE_4CTB_EVALUATION
node_validity = (blk_8x8_mask == 0xf);
#if ENABLE_CU_TREE_CULLING
{
cur_ctb_cu_tree_t *ps_32x32_root;
switch(e_parent_blk_pos)
{
case POS_TL:
{
ps_32x32_root = ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_tl;
break;
}
case POS_TR:
{
ps_32x32_root = ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_tr;
break;
}
case POS_BL:
{
ps_32x32_root = ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_bl;
break;
}
case POS_BR:
{
ps_32x32_root = ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_br;
break;
}
}
if(ps_32x32_root->is_node_valid)
{
node_validity =
node_validity &&
!ps_ctb_cluster_info
->au1_is_16x16_blk_split[(S32)(e_parent_blk_pos << 2) + e_cur_blk_pos];
children_nodes_required = !node_validity;
}
}
#endif
break;
#else
if(ipe_decision_precedence)
{
S32 merge_flag_16 = (ps_cur_ipe_ctb->as_intra32_analyse[e_parent_blk_pos]
.as_intra16_analyse[e_cur_blk_pos]
.b1_merge_flag);
S32 valid_flag = (blk_8x8_mask == 0xf);
node_validity = merge_flag_16 && valid_flag;
}
else
{
node_validity = (blk_8x8_mask == 0xf);
}
break;
#endif
}
case 3:
{
S32 blk_8x8_mask =
ps_ctb_cluster_info
->pi4_blk_8x8_mask[(S32)(e_grandparent_blk_pos << 2) + e_parent_blk_pos];
S32 merge_flag_16 = (ps_cur_ipe_ctb->as_intra32_analyse[e_grandparent_blk_pos]
.as_intra16_analyse[e_parent_blk_pos]
.b1_merge_flag);
S32 merge_flag_32 =
(ps_cur_ipe_ctb->as_intra32_analyse[e_grandparent_blk_pos].b1_merge_flag);
intra_eval_enable = !merge_flag_16 || !merge_flag_32;
inter_eval_enable = 1;
children_nodes_required = 0;
#if 1 //!PROCESS_GT_1CTB_VIA_CU_RECUR_IN_FAST_PRESETS
if(e_quality_preset >= ME_HIGH_QUALITY)
{
node_validity = ((blk_8x8_mask & (1 << e_cur_blk_pos)) || 0);
break;
}
#endif
#if ENABLE_4CTB_EVALUATION
node_validity = ((blk_8x8_mask & (1 << e_cur_blk_pos)) || 0);
break;
#else
{
cur_ctb_cu_tree_t *ps_32x32_root;
cur_ctb_cu_tree_t *ps_16x16_root;
cluster_32x32_blk_t *ps_32x32_blk;
switch(e_grandparent_blk_pos)
{
case POS_TL:
{
ps_32x32_root = ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_tl;
break;
}
case POS_TR:
{
ps_32x32_root = ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_tr;
break;
}
case POS_BL:
{
ps_32x32_root = ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_bl;
break;
}
case POS_BR:
{
ps_32x32_root = ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_br;
break;
}
}
switch(e_parent_blk_pos)
{
case POS_TL:
{
ps_16x16_root = ps_32x32_root->ps_child_node_tl;
break;
}
case POS_TR:
{
ps_16x16_root = ps_32x32_root->ps_child_node_tr;
break;
}
case POS_BL:
{
ps_16x16_root = ps_32x32_root->ps_child_node_bl;
break;
}
case POS_BR:
{
ps_16x16_root = ps_32x32_root->ps_child_node_br;
break;
}
}
ps_32x32_blk = &ps_ctb_cluster_info->ps_32x32_blk[e_grandparent_blk_pos];
node_validity = ((blk_8x8_mask & (1 << e_cur_blk_pos)) || 0) &&
((!ps_32x32_root->is_node_valid) ||
(ps_32x32_blk->num_clusters_with_weak_sdi_density > 0) ||
(!ps_16x16_root->is_node_valid));
break;
}
#endif
}
}
/* Fill the current cu_tree node */
ps_cu_tree->is_node_valid = node_validity;
ps_cu_tree->u1_intra_eval_enable = intra_eval_enable;
ps_cu_tree->u1_inter_eval_enable = inter_eval_enable;
if(children_nodes_required)
{
tree_depth++;
hme_populate_cu_tree(
ps_ctb_cluster_info,
ps_cu_tree->ps_child_node_tl,
tree_depth,
e_quality_preset,
e_parent_blk_pos,
e_cur_blk_pos,
POS_TL);
hme_populate_cu_tree(
ps_ctb_cluster_info,
ps_cu_tree->ps_child_node_tr,
tree_depth,
e_quality_preset,
e_parent_blk_pos,
e_cur_blk_pos,
POS_TR);
hme_populate_cu_tree(
ps_ctb_cluster_info,
ps_cu_tree->ps_child_node_bl,
tree_depth,
e_quality_preset,
e_parent_blk_pos,
e_cur_blk_pos,
POS_BL);
hme_populate_cu_tree(
ps_ctb_cluster_info,
ps_cu_tree->ps_child_node_br,
tree_depth,
e_quality_preset,
e_parent_blk_pos,
e_cur_blk_pos,
POS_BR);
}
}
/**
********************************************************************************
* @fn void hme_analyse_mv_clustering
* (
* search_results_t *ps_search_results,
* ipe_l0_ctb_analyse_for_me_t *ps_cur_ipe_ctb,
* cur_ctb_cu_tree_t *ps_cu_tree
* )
*
* @brief Implementation for the clustering algorithm
*
* @param[in] ps_search_results: structure containing 16x16 block results
*
* @param[in] ps_cur_ipe_ctb : output container for ipe analyses
*
* @param[out] ps_cu_tree : represents CU tree used in CU recursion
*
* @return None
********************************************************************************
*/
void hme_analyse_mv_clustering(
search_results_t *ps_search_results,
inter_cu_results_t *ps_16x16_cu_results,
inter_cu_results_t *ps_8x8_cu_results,
ctb_cluster_info_t *ps_ctb_cluster_info,
S08 *pi1_future_list,
S08 *pi1_past_list,
S32 bidir_enabled,
ME_QUALITY_PRESETS_T e_quality_preset)
{
cluster_16x16_blk_t *ps_blk_16x16;
cluster_32x32_blk_t *ps_blk_32x32;
cluster_64x64_blk_t *ps_blk_64x64;
part_type_results_t *ps_best_result;
pu_result_t *aps_part_result[MAX_NUM_PARTS];
pu_result_t *aps_inferior_parts[MAX_NUM_PARTS];
PART_ID_T e_part_id;
PART_TYPE_T e_part_type;
S32 enable_64x64_merge;
S32 i, j, k;
S32 mvx, mvy;
S32 num_parts;
S32 ref_idx;
S32 ai4_pred_mode[MAX_NUM_PARTS];
S32 num_32x32_merges = 0;
/*****************************************/
/*****************************************/
/********* Enter ye who is HQ ************/
/*****************************************/
/*****************************************/
ps_blk_64x64 = ps_ctb_cluster_info->ps_64x64_blk;
/* Initialise data in each of the clusters */
for(i = 0; i < 16; i++)
{
ps_blk_16x16 = &ps_ctb_cluster_info->ps_16x16_blk[i];
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
if(e_quality_preset < ME_HIGH_QUALITY)
{
hme_init_clusters_16x16(ps_blk_16x16, bidir_enabled);
}
else
{
ps_blk_16x16->best_inter_cost = 0;
ps_blk_16x16->intra_mv_area = 0;
}
#else
hme_init_clusters_16x16(ps_blk_16x16, bidir_enabled);
#endif
}
for(i = 0; i < 4; i++)
{
ps_blk_32x32 = &ps_ctb_cluster_info->ps_32x32_blk[i];
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
if(e_quality_preset < ME_HIGH_QUALITY)
{
hme_init_clusters_32x32(ps_blk_32x32, bidir_enabled);
}
else
{
ps_blk_32x32->best_inter_cost = 0;
ps_blk_32x32->intra_mv_area = 0;
}
#else
hme_init_clusters_32x32(ps_blk_32x32, bidir_enabled);
#endif
}
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
if(e_quality_preset < ME_HIGH_QUALITY)
{
hme_init_clusters_64x64(ps_blk_64x64, bidir_enabled);
}
else
{
ps_blk_64x64->best_inter_cost = 0;
ps_blk_64x64->intra_mv_area = 0;
}
#else
hme_init_clusters_64x64(ps_blk_64x64, bidir_enabled);
#endif
/* Initialise data for all nodes in the CU tree */
hme_build_cu_tree(
ps_ctb_cluster_info, ps_ctb_cluster_info->ps_cu_tree_root, 0, POS_NA, POS_NA, POS_NA);
if(e_quality_preset >= ME_HIGH_QUALITY)
{
memset(ps_ctb_cluster_info->au1_is_16x16_blk_split, 1, 16 * sizeof(U08));
}
#if ENABLE_UNIFORM_CU_SIZE_16x16 || ENABLE_UNIFORM_CU_SIZE_8x8
return;
#endif
for(i = 0; i < 16; i++)
{
S32 blk_8x8_mask;
S32 is_16x16_blk_valid;
S32 num_clusters_updated;
S32 num_clusters;
blk_8x8_mask = ps_ctb_cluster_info->pi4_blk_8x8_mask[i];
ps_blk_16x16 = &ps_ctb_cluster_info->ps_16x16_blk[i];
is_16x16_blk_valid = (blk_8x8_mask == 0xf);
if(is_16x16_blk_valid)
{
/* Use 8x8 data when 16x16 CU is split */
if(ps_search_results[i].u1_split_flag)
{
S32 blk_8x8_idx = i << 2;
num_parts = 4;
e_part_type = PRT_NxN;
for(j = 0; j < num_parts; j++, blk_8x8_idx++)
{
/* Only 2Nx2N partition supported for 8x8 block */
ASSERT(
ps_8x8_cu_results[blk_8x8_idx].ps_best_results[0].u1_part_type ==
((PART_TYPE_T)PRT_2Nx2N));
aps_part_result[j] =
&ps_8x8_cu_results[blk_8x8_idx].ps_best_results[0].as_pu_results[0];
aps_inferior_parts[j] =
&ps_8x8_cu_results[blk_8x8_idx].ps_best_results[1].as_pu_results[0];
ai4_pred_mode[j] = (aps_part_result[j]->pu.b2_pred_mode);
}
}
else
{
ps_best_result = &ps_16x16_cu_results[i].ps_best_results[0];
e_part_type = (PART_TYPE_T)ps_best_result->u1_part_type;
num_parts = gau1_num_parts_in_part_type[e_part_type];
for(j = 0; j < num_parts; j++)
{
aps_part_result[j] = &ps_best_result->as_pu_results[j];
aps_inferior_parts[j] = &ps_best_result[1].as_pu_results[j];
ai4_pred_mode[j] = (aps_part_result[j]->pu.b2_pred_mode);
}
ps_ctb_cluster_info->au1_is_16x16_blk_split[i] = 0;
}
for(j = 0; j < num_parts; j++)
{
pu_result_t *ps_part_result = aps_part_result[j];
S32 num_mvs = ((ai4_pred_mode[j] > 1) + 1);
e_part_id = ge_part_type_to_part_id[e_part_type][j];
/* Skip clustering if best mode is intra */
if((ps_part_result->pu.b1_intra_flag))
{
ps_blk_16x16->intra_mv_area += gai4_partition_area[e_part_id];
ps_blk_16x16->best_inter_cost += aps_inferior_parts[j]->i4_tot_cost;
continue;
}
else
{
ps_blk_16x16->best_inter_cost += ps_part_result->i4_tot_cost;
}
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
if(e_quality_preset >= ME_HIGH_QUALITY)
{
continue;
}
#endif
for(k = 0; k < num_mvs; k++)
{
mv_t *ps_mv;
pu_mv_t *ps_pu_mv = &ps_part_result->pu.mv;
S32 is_l0_mv = ((ai4_pred_mode[j] == 2) && !k) || (ai4_pred_mode[j] == 0);
ps_mv = (is_l0_mv) ? (&ps_pu_mv->s_l0_mv) : (&ps_pu_mv->s_l1_mv);
mvx = ps_mv->i2_mvx;
mvy = ps_mv->i2_mvy;
ref_idx = (is_l0_mv) ? pi1_past_list[ps_pu_mv->i1_l0_ref_idx]
: pi1_future_list[ps_pu_mv->i1_l1_ref_idx];
num_clusters = ps_blk_16x16->num_clusters;
hme_find_and_update_clusters(
ps_blk_16x16->as_cluster_data,
&(ps_blk_16x16->num_clusters),
mvx,
mvy,
ref_idx,
ps_part_result->i4_sdi,
e_part_id,
(ai4_pred_mode[j] == 2));
num_clusters_updated = (ps_blk_16x16->num_clusters);
ps_blk_16x16->au1_num_clusters[ref_idx] +=
(num_clusters_updated - num_clusters);
}
}
}
}
/* Search for 32x32 clusters */
for(i = 0; i < 4; i++)
{
S32 num_clusters_merged;
S32 is_32x32_blk_valid = (ps_ctb_cluster_info->blk_32x32_mask & (1 << i)) || 0;
if(is_32x32_blk_valid)
{
ps_blk_32x32 = &ps_ctb_cluster_info->ps_32x32_blk[i];
ps_blk_16x16 = &ps_ctb_cluster_info->ps_16x16_blk[i << 2];
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
if(e_quality_preset >= ME_HIGH_QUALITY)
{
for(j = 0; j < 4; j++, ps_blk_16x16++)
{
ps_blk_32x32->intra_mv_area += ps_blk_16x16->intra_mv_area;
ps_blk_32x32->best_inter_cost += ps_blk_16x16->best_inter_cost;
}
continue;
}
#endif
hme_update_32x32_clusters(ps_blk_32x32, ps_blk_16x16);
if((ps_blk_32x32->num_clusters >= MAX_NUM_CLUSTERS_IN_VALID_32x32_BLK))
{
num_clusters_merged = hme_try_merge_clusters_blksize_gt_16(
ps_blk_32x32->as_cluster_data, (ps_blk_32x32->num_clusters));
if(num_clusters_merged)
{
ps_blk_32x32->num_clusters -= num_clusters_merged;
UPDATE_CLUSTER_METADATA_POST_MERGE(ps_blk_32x32);
}
}
}
}
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
/* Eliminate outlier 32x32 clusters */
if(e_quality_preset < ME_HIGH_QUALITY)
#endif
{
hme_boot_out_outlier(ps_ctb_cluster_info, 32);
/* Find best_uni_ref and best_alt_ref */
hme_find_top_ref_ids(ps_ctb_cluster_info, bidir_enabled, 32);
}
/* Populate the CU tree for depths 1 and higher */
{
cur_ctb_cu_tree_t *ps_tree_root = ps_ctb_cluster_info->ps_cu_tree_root;
cur_ctb_cu_tree_t *ps_tl = ps_tree_root->ps_child_node_tl;
cur_ctb_cu_tree_t *ps_tr = ps_tree_root->ps_child_node_tr;
cur_ctb_cu_tree_t *ps_bl = ps_tree_root->ps_child_node_bl;
cur_ctb_cu_tree_t *ps_br = ps_tree_root->ps_child_node_br;
hme_populate_cu_tree(
ps_ctb_cluster_info, ps_tl, 1, e_quality_preset, POS_NA, POS_NA, POS_TL);
num_32x32_merges += (ps_tl->is_node_valid == 1);
hme_populate_cu_tree(
ps_ctb_cluster_info, ps_tr, 1, e_quality_preset, POS_NA, POS_NA, POS_TR);
num_32x32_merges += (ps_tr->is_node_valid == 1);
hme_populate_cu_tree(
ps_ctb_cluster_info, ps_bl, 1, e_quality_preset, POS_NA, POS_NA, POS_BL);
num_32x32_merges += (ps_bl->is_node_valid == 1);
hme_populate_cu_tree(
ps_ctb_cluster_info, ps_br, 1, e_quality_preset, POS_NA, POS_NA, POS_BR);
num_32x32_merges += (ps_br->is_node_valid == 1);
}
#if !ENABLE_4CTB_EVALUATION
if(e_quality_preset < ME_HIGH_QUALITY)
{
enable_64x64_merge = (num_32x32_merges >= 3);
}
#else
if(e_quality_preset < ME_HIGH_QUALITY)
{
enable_64x64_merge = 1;
}
#endif
#if 1 //!PROCESS_GT_1CTB_VIA_CU_RECUR_IN_FAST_PRESETS
if(e_quality_preset >= ME_HIGH_QUALITY)
{
enable_64x64_merge = 1;
}
#else
if(e_quality_preset >= ME_HIGH_QUALITY)
{
enable_64x64_merge = (num_32x32_merges >= 3);
}
#endif
if(enable_64x64_merge)
{
S32 num_clusters_merged;
ps_blk_32x32 = &ps_ctb_cluster_info->ps_32x32_blk[0];
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
if(e_quality_preset >= ME_HIGH_QUALITY)
{
for(j = 0; j < 4; j++, ps_blk_32x32++)
{
ps_blk_64x64->intra_mv_area += ps_blk_32x32->intra_mv_area;
ps_blk_64x64->best_inter_cost += ps_blk_32x32->best_inter_cost;
}
}
else
#endif
{
hme_update_64x64_clusters(ps_blk_64x64, ps_blk_32x32);
if((ps_blk_64x64->num_clusters >= MAX_NUM_CLUSTERS_IN_VALID_64x64_BLK))
{
num_clusters_merged = hme_try_merge_clusters_blksize_gt_16(
ps_blk_64x64->as_cluster_data, (ps_blk_64x64->num_clusters));
if(num_clusters_merged)
{
ps_blk_64x64->num_clusters -= num_clusters_merged;
UPDATE_CLUSTER_METADATA_POST_MERGE(ps_blk_64x64);
}
}
}
#if !ENABLE_4CTB_EVALUATION
if(e_quality_preset < ME_HIGH_QUALITY)
{
S32 best_inter_cost = ps_blk_64x64->best_inter_cost;
S32 best_intra_cost =
((ps_ctb_cluster_info->ps_cur_ipe_ctb->i4_best64x64_intra_cost +
ps_ctb_cluster_info->i4_frame_qstep *
ps_ctb_cluster_info->i4_frame_qstep_multiplier * 16) < 0)
? MAX_32BIT_VAL
: (ps_ctb_cluster_info->ps_cur_ipe_ctb->i4_best64x64_intra_cost +
ps_ctb_cluster_info->i4_frame_qstep *
ps_ctb_cluster_info->i4_frame_qstep_multiplier * 16);
S32 best_cost = (best_inter_cost > best_intra_cost) ? best_intra_cost : best_inter_cost;
S32 cost_differential = (best_inter_cost - best_cost);
enable_64x64_merge =
((ALL_INTER_COST_DIFF_THR * best_cost) >= (100 * cost_differential));
}
#endif
}
if(enable_64x64_merge)
{
#if !USE_CLUSTER_DATA_AS_BLK_MERGE_CANDTS
if(e_quality_preset < ME_HIGH_QUALITY)
#endif
{
hme_boot_out_outlier(ps_ctb_cluster_info, 64);
hme_find_top_ref_ids(ps_ctb_cluster_info, bidir_enabled, 64);
}
hme_populate_cu_tree(
ps_ctb_cluster_info,
ps_ctb_cluster_info->ps_cu_tree_root,
0,
e_quality_preset,
POS_NA,
POS_NA,
POS_NA);
}
}
#endif
static __inline void hme_merge_prms_init(
hme_merge_prms_t *ps_prms,
layer_ctxt_t *ps_curr_layer,
refine_prms_t *ps_refine_prms,
me_frm_ctxt_t *ps_me_ctxt,
range_prms_t *ps_range_prms_rec,
range_prms_t *ps_range_prms_inp,
mv_grid_t **pps_mv_grid,
inter_ctb_prms_t *ps_inter_ctb_prms,
S32 i4_num_pred_dir,
S32 i4_32x32_id,
BLK_SIZE_T e_blk_size,
ME_QUALITY_PRESETS_T e_me_quality_presets)
{
S32 i4_use_rec = ps_refine_prms->i4_use_rec_in_fpel;
S32 i4_cu_16x16 = (BLK_32x32 == e_blk_size) ? (i4_32x32_id << 2) : 0;
/* Currently not enabling segmentation info from prev layers */
ps_prms->i4_seg_info_avail = 0;
ps_prms->i4_part_mask = 0;
/* Number of reference pics in which to do merge */
ps_prms->i4_num_ref = i4_num_pred_dir;
/* Layer ctxt info */
ps_prms->ps_layer_ctxt = ps_curr_layer;
ps_prms->ps_inter_ctb_prms = ps_inter_ctb_prms;
/* Top left, top right, bottom left and bottom right 16x16 units */
if(BLK_32x32 == e_blk_size)
{
ps_prms->ps_results_tl = &ps_me_ctxt->as_search_results_16x16[i4_cu_16x16];
ps_prms->ps_results_tr = &ps_me_ctxt->as_search_results_16x16[i4_cu_16x16 + 1];
ps_prms->ps_results_bl = &ps_me_ctxt->as_search_results_16x16[i4_cu_16x16 + 2];
ps_prms->ps_results_br = &ps_me_ctxt->as_search_results_16x16[i4_cu_16x16 + 3];
/* Merge results stored here */
ps_prms->ps_results_merge = &ps_me_ctxt->as_search_results_32x32[i4_32x32_id];
/* This could be lesser than the number of 16x16results generated*/
/* For now, keeping it to be same */
ps_prms->i4_num_inp_results = ps_refine_prms->i4_num_fpel_results;
ps_prms->ps_8x8_cu_results = &ps_me_ctxt->as_cu8x8_results[i4_32x32_id << 4];
ps_prms->ps_results_grandchild = NULL;
}
else
{
ps_prms->ps_results_tl = &ps_me_ctxt->as_search_results_32x32[0];
ps_prms->ps_results_tr = &ps_me_ctxt->as_search_results_32x32[1];
ps_prms->ps_results_bl = &ps_me_ctxt->as_search_results_32x32[2];
ps_prms->ps_results_br = &ps_me_ctxt->as_search_results_32x32[3];
/* Merge results stored here */
ps_prms->ps_results_merge = &ps_me_ctxt->s_search_results_64x64;
ps_prms->i4_num_inp_results = ps_refine_prms->i4_num_32x32_merge_results;
ps_prms->ps_8x8_cu_results = &ps_me_ctxt->as_cu8x8_results[0];
ps_prms->ps_results_grandchild = ps_me_ctxt->as_search_results_16x16;
}
if(i4_use_rec)
{
WORD32 ref_ctr;
for(ref_ctr = 0; ref_ctr < MAX_NUM_REF; ref_ctr++)
{
ps_prms->aps_mv_range[ref_ctr] = &ps_range_prms_rec[ref_ctr];
}
}
else
{
WORD32 ref_ctr;
for(ref_ctr = 0; ref_ctr < MAX_NUM_REF; ref_ctr++)
{
ps_prms->aps_mv_range[ref_ctr] = &ps_range_prms_inp[ref_ctr];
}
}
ps_prms->i4_use_rec = i4_use_rec;
ps_prms->pf_mv_cost_compute = compute_mv_cost_implicit_high_speed;
ps_prms->pps_mv_grid = pps_mv_grid;
ps_prms->log_ctb_size = ps_me_ctxt->log_ctb_size;
ps_prms->e_quality_preset = e_me_quality_presets;
ps_prms->pi1_future_list = ps_me_ctxt->ai1_future_list;
ps_prms->pi1_past_list = ps_me_ctxt->ai1_past_list;
ps_prms->ps_cluster_info = ps_me_ctxt->ps_ctb_cluster_info;
}
/**
********************************************************************************
* @fn void hme_refine(me_ctxt_t *ps_ctxt,
* refine_layer_prms_t *ps_refine_prms)
*
* @brief Top level entry point for refinement ME
*
* @param[in,out] ps_ctxt: ME Handle
*
* @param[in] ps_refine_prms : refinement layer prms
*
* @return None
********************************************************************************
*/
void hme_refine(
me_ctxt_t *ps_thrd_ctxt,
refine_prms_t *ps_refine_prms,
PF_EXT_UPDATE_FXN_T pf_ext_update_fxn,
layer_ctxt_t *ps_coarse_layer,
multi_thrd_ctxt_t *ps_multi_thrd_ctxt,
S32 lyr_job_type,
S32 thrd_id,
S32 me_frm_id,
pre_enc_L0_ipe_encloop_ctxt_t *ps_l0_ipe_input)
{
inter_ctb_prms_t s_common_frm_prms;
BLK_SIZE_T e_search_blk_size, e_result_blk_size;
WORD32 i4_me_frm_id = me_frm_id % MAX_NUM_ME_PARALLEL;
me_frm_ctxt_t *ps_ctxt = ps_thrd_ctxt->aps_me_frm_prms[i4_me_frm_id];
ME_QUALITY_PRESETS_T e_me_quality_presets =
ps_thrd_ctxt->s_init_prms.s_me_coding_tools.e_me_quality_presets;
WORD32 num_rows_proc = 0;
WORD32 num_act_ref_pics;
WORD16 i2_prev_enc_frm_max_mv_y;
WORD32 i4_idx_dvsr_p = ps_multi_thrd_ctxt->i4_idx_dvsr_p;
/*************************************************************************/
/* Complexity of search: Low to High */
/*************************************************************************/
SEARCH_COMPLEXITY_T e_search_complexity;
/*************************************************************************/
/* to store the PU results which are passed to the decide_part_types */
/* as input prms. Multiplied by 4 as the max number of Ref in a List is 4*/
/*************************************************************************/
pu_result_t as_pu_results[2][TOT_NUM_PARTS][MAX_NUM_RESULTS_PER_PART_LIST];
inter_pu_results_t as_inter_pu_results[4];
inter_pu_results_t *ps_pu_results = as_inter_pu_results;
/*************************************************************************/
/* Config parameter structures for varius ME submodules */
/*************************************************************************/
hme_merge_prms_t s_merge_prms_32x32_tl, s_merge_prms_32x32_tr;
hme_merge_prms_t s_merge_prms_32x32_bl, s_merge_prms_32x32_br;
hme_merge_prms_t s_merge_prms_64x64;
hme_search_prms_t s_search_prms_blk;
mvbank_update_prms_t s_mv_update_prms;
hme_ctb_prms_t s_ctb_prms;
hme_subpel_prms_t s_subpel_prms;
fullpel_refine_ctxt_t *ps_fullpel_refine_ctxt = ps_ctxt->ps_fullpel_refine_ctxt;
ctb_cluster_info_t *ps_ctb_cluster_info;
fpel_srch_cand_init_data_t s_srch_cand_init_data;
/* 4 bits (LSBs) of this variable control merge of 4 32x32 CUs in CTB */
S32 en_merge_32x32;
/* 5 lsb's specify whether or not merge algorithm is required */
/* to be executed or not. Relevant only in PQ. Ought to be */
/* used in conjunction with en_merge_32x32 and */
/* ps_ctb_bound_attrs->u1_merge_to_64x64_flag. This is */
/* required when all children are deemed to be intras */
S32 en_merge_execution;
/*************************************************************************/
/* All types of search candidates for predictor based search. */
/*************************************************************************/
S32 num_init_candts = 0;
S32 i4_num_act_ref_l0 = ps_ctxt->s_frm_prms.u1_num_active_ref_l0;
S32 i4_num_act_ref_l1 = ps_ctxt->s_frm_prms.u1_num_active_ref_l1;
search_candt_t *ps_search_candts, as_search_candts[MAX_INIT_CANDTS];
search_node_t as_top_neighbours[4], as_left_neighbours[3];
pf_get_wt_inp fp_get_wt_inp;
search_node_t as_unique_search_nodes[MAX_INIT_CANDTS * 9];
U32 au4_unique_node_map[MAP_X_MAX * 2];
/* Controls the boundary attributes of CTB, whether it has 64x64 or not */
ctb_boundary_attrs_t *ps_ctb_bound_attrs;
/*************************************************************************/
/* points ot the search results for the blk level search (8x8/16x16) */
/*************************************************************************/
search_results_t *ps_search_results;
/*************************************************************************/
/* Coordinates */
/*************************************************************************/
S32 blk_x, blk_y, i4_ctb_x, i4_ctb_y, tile_col_idx, blk_id_in_ctb;
S32 pos_x, pos_y;
S32 blk_id_in_full_ctb;
/*************************************************************************/
/* Related to dimensions of block being searched and pic dimensions */
/*************************************************************************/
S32 blk_4x4_to_16x16;
S32 blk_wd, blk_ht, blk_size_shift;
S32 i4_pic_wd, i4_pic_ht, num_blks_in_this_ctb;
S32 num_results_prev_layer;
/*************************************************************************/
/* Size of a basic unit for this layer. For non encode layers, we search */
/* in block sizes of 8x8. For encode layers, though we search 16x16s the */
/* basic unit size is the ctb size. */
/*************************************************************************/
S32 unit_size;
/*************************************************************************/
/* Local variable storing results of any 4 CU merge to bigger CU */
/*************************************************************************/
CU_MERGE_RESULT_T e_merge_result;
/*************************************************************************/
/* This mv grid stores results during and after fpel search, during */
/* merge, subpel and bidirect refinements stages. 2 instances of this are*/
/* meant for the 2 directions of search (l0 and l1). */
/*************************************************************************/
mv_grid_t *aps_mv_grid[2];
/*************************************************************************/
/* Pointers to context in current and coarser layers */
/*************************************************************************/
layer_ctxt_t *ps_curr_layer, *ps_prev_layer;
/*************************************************************************/
/* to store mv range per blk, and picture limit, allowed search range */
/* range prms in hpel and qpel units as well */
/*************************************************************************/
range_prms_t as_range_prms_inp[MAX_NUM_REF], as_range_prms_rec[MAX_NUM_REF];
range_prms_t s_pic_limit_inp, s_pic_limit_rec, as_mv_limit[MAX_NUM_REF];
range_prms_t as_range_prms_hpel[MAX_NUM_REF], as_range_prms_qpel[MAX_NUM_REF];
/*************************************************************************/
/* These variables are used to track number of references at different */
/* stages of ME. */
/*************************************************************************/
S32 i4_num_pred_dir;
S32 i4_num_ref_each_dir, i, i4_num_ref_prev_layer;
S32 lambda_recon = ps_refine_prms->lambda_recon;
/* Counts successful merge to 32x32 every CTB (0-4) */
S32 merge_count_32x32;
S32 ai4_id_coloc[14], ai4_id_Z[2];
U08 au1_search_candidate_list_index[2];
S32 ai4_num_coloc_cands[2];
U08 u1_pred_dir, u1_pred_dir_ctr;
/*************************************************************************/
/* Input pointer and stride */
/*************************************************************************/
U08 *pu1_inp;
S32 i4_inp_stride;
S32 end_of_frame;
S32 num_sync_units_in_row, num_sync_units_in_tile;
/*************************************************************************/
/* Indicates whether the all 4 8x8 blks are valid in the 16x16 blk in the*/
/* encode layer. If not 15, then 1 or more 8x8 blks not valid. Means that*/
/* we need to stop merges and force 8x8 CUs for that 16x16 blk */
/*************************************************************************/
S32 blk_8x8_mask;
S32 ai4_blk_8x8_mask[16];
U08 au1_is_64x64Blk_noisy[1];
U08 au1_is_32x32Blk_noisy[4];
U08 au1_is_16x16Blk_noisy[16];
ihevce_cmn_opt_func_t *ps_cmn_utils_optimised_function_list =
ps_thrd_ctxt->ps_cmn_utils_optimised_function_list;
ihevce_me_optimised_function_list_t *ps_me_optimised_function_list =
((ihevce_me_optimised_function_list_t *)ps_thrd_ctxt->pv_me_optimised_function_list);
ASSERT(ps_refine_prms->i4_layer_id < ps_ctxt->num_layers - 1);
/*************************************************************************/
/* Pointers to current and coarse layer are needed for projection */
/* Pointer to prev layer are needed for other candts like coloc */
/*************************************************************************/
ps_curr_layer = ps_ctxt->ps_curr_descr->aps_layers[ps_refine_prms->i4_layer_id];
ps_prev_layer = hme_get_past_layer_ctxt(
ps_thrd_ctxt, ps_ctxt, ps_refine_prms->i4_layer_id, ps_multi_thrd_ctxt->i4_num_me_frm_pllel);
num_results_prev_layer = ps_coarse_layer->ps_layer_mvbank->i4_num_mvs_per_ref;
/* Function pointer is selected based on the C vc X86 macro */
fp_get_wt_inp = ps_me_optimised_function_list->pf_get_wt_inp_ctb;
i4_inp_stride = ps_curr_layer->i4_inp_stride;
i4_pic_wd = ps_curr_layer->i4_wd;
i4_pic_ht = ps_curr_layer->i4_ht;
e_search_complexity = ps_refine_prms->e_search_complexity;
end_of_frame = 0;
/* This points to all the initial candts */
ps_search_candts = &as_search_candts[0];
/* mv grid being huge strucutre is part of context */
aps_mv_grid[0] = &ps_ctxt->as_mv_grid[0];
aps_mv_grid[1] = &ps_ctxt->as_mv_grid[1];
/*************************************************************************/
/* If the current layer is encoded (since it may be multicast or final */
/* layer (finest)), then we use 16x16 blk size with some selected parts */
/* If the current layer is not encoded, then we use 8x8 blk size, with */
/* enable or disable of 4x4 partitions depending on the input prms */
/*************************************************************************/
e_search_blk_size = BLK_16x16;
blk_wd = blk_ht = 16;
blk_size_shift = 4;
e_result_blk_size = BLK_8x8;
s_mv_update_prms.i4_shift = 1;
if(ps_coarse_layer->ps_layer_mvbank->e_blk_size == BLK_4x4)
{
blk_4x4_to_16x16 = 1;
}
else
{
blk_4x4_to_16x16 = 0;
}
unit_size = 1 << ps_ctxt->log_ctb_size;
s_search_prms_blk.i4_inp_stride = unit_size;
/* This is required to properly update the layer mv bank */
s_mv_update_prms.e_search_blk_size = e_search_blk_size;
s_search_prms_blk.e_blk_size = e_search_blk_size;
/*************************************************************************/
/* If current layer is explicit, then the number of ref frames are to */
/* be same as previous layer. Else it will be 2 */
/*************************************************************************/
i4_num_ref_prev_layer = ps_coarse_layer->ps_layer_mvbank->i4_num_ref;
i4_num_pred_dir =
(ps_ctxt->s_frm_prms.bidir_enabled && (i4_num_act_ref_l0 > 0) && (i4_num_act_ref_l1 > 0)) +
1;
#if USE_MODIFIED == 1
s_search_prms_blk.pf_mv_cost_compute = compute_mv_cost_implicit_high_speed_modified;
#else
s_search_prms_blk.pf_mv_cost_compute = compute_mv_cost_implicit_high_speed;
#endif
i4_num_pred_dir = MIN(i4_num_pred_dir, i4_num_ref_prev_layer);
if(i4_num_ref_prev_layer <= 2)
{
i4_num_ref_each_dir = 1;
}
else
{
i4_num_ref_each_dir = i4_num_ref_prev_layer >> 1;
}
s_mv_update_prms.i4_num_ref = i4_num_pred_dir;
s_mv_update_prms.i4_num_results_to_store =
MIN((ps_ctxt->s_frm_prms.bidir_enabled) ? ps_curr_layer->ps_layer_mvbank->i4_num_mvs_per_ref
: (i4_num_act_ref_l0 > 1) + 1,
ps_refine_prms->i4_num_results_per_part);
/*************************************************************************/
/* Initialization of merge params for 16x16 to 32x32 merge. */
/* There are 4 32x32 units in a CTB, so 4 param structures initialized */
/*************************************************************************/
{
hme_merge_prms_t *aps_merge_prms[4];
aps_merge_prms[0] = &s_merge_prms_32x32_tl;
aps_merge_prms[1] = &s_merge_prms_32x32_tr;
aps_merge_prms[2] = &s_merge_prms_32x32_bl;
aps_merge_prms[3] = &s_merge_prms_32x32_br;
for(i = 0; i < 4; i++)
{
hme_merge_prms_init(
aps_merge_prms[i],
ps_curr_layer,
ps_refine_prms,
ps_ctxt,
as_range_prms_rec,
as_range_prms_inp,
&aps_mv_grid[0],
&s_common_frm_prms,
i4_num_pred_dir,
i,
BLK_32x32,
e_me_quality_presets);
}
}
/*************************************************************************/
/* Initialization of merge params for 32x32 to 64x64 merge. */
/* There are 4 32x32 units in a CTB, so only 1 64x64 CU can be in CTB */
/*************************************************************************/
{
hme_merge_prms_init(
&s_merge_prms_64x64,
ps_curr_layer,
ps_refine_prms,
ps_ctxt,
as_range_prms_rec,
as_range_prms_inp,
&aps_mv_grid[0],
&s_common_frm_prms,
i4_num_pred_dir,
0,
BLK_64x64,
e_me_quality_presets);
}
/* Pointers to cu_results are initialised here */
{
WORD32 i;
ps_ctxt->s_search_results_64x64.ps_cu_results = &ps_ctxt->s_cu64x64_results;
for(i = 0; i < 4; i++)
{
ps_ctxt->as_search_results_32x32[i].ps_cu_results = &ps_ctxt->as_cu32x32_results[i];
}
for(i = 0; i < 16; i++)
{
ps_ctxt->as_search_results_16x16[i].ps_cu_results = &ps_ctxt->as_cu16x16_results[i];
}
}
/*************************************************************************/
/* SUBPEL Params initialized here */
/*************************************************************************/
{
s_subpel_prms.ps_search_results_16x16 = &ps_ctxt->as_search_results_16x16[0];
s_subpel_prms.ps_search_results_32x32 = &ps_ctxt->as_search_results_32x32[0];
s_subpel_prms.ps_search_results_64x64 = &ps_ctxt->s_search_results_64x64;
s_subpel_prms.i4_num_16x16_candts = ps_refine_prms->i4_num_fpel_results;
s_subpel_prms.i4_num_32x32_candts = ps_refine_prms->i4_num_32x32_merge_results;
s_subpel_prms.i4_num_64x64_candts = ps_refine_prms->i4_num_64x64_merge_results;
s_subpel_prms.i4_num_steps_hpel_refine = ps_refine_prms->i4_num_steps_hpel_refine;
s_subpel_prms.i4_num_steps_qpel_refine = ps_refine_prms->i4_num_steps_qpel_refine;
s_subpel_prms.i4_use_satd = ps_refine_prms->i4_use_satd_subpel;
s_subpel_prms.i4_inp_stride = unit_size;
s_subpel_prms.u1_max_subpel_candts_2Nx2N = ps_refine_prms->u1_max_subpel_candts_2Nx2N;
s_subpel_prms.u1_max_subpel_candts_NxN = ps_refine_prms->u1_max_subpel_candts_NxN;
s_subpel_prms.u1_subpel_candt_threshold = ps_refine_prms->u1_subpel_candt_threshold;
s_subpel_prms.pf_qpel_interp = ps_me_optimised_function_list->pf_qpel_interp_avg_generic;
{
WORD32 ref_ctr;
for(ref_ctr = 0; ref_ctr < MAX_NUM_REF; ref_ctr++)
{
s_subpel_prms.aps_mv_range_hpel[ref_ctr] = &as_range_prms_hpel[ref_ctr];
s_subpel_prms.aps_mv_range_qpel[ref_ctr] = &as_range_prms_qpel[ref_ctr];
}
}
s_subpel_prms.pi2_inp_bck = ps_ctxt->pi2_inp_bck;
#if USE_MODIFIED == 0
s_subpel_prms.pf_mv_cost_compute = compute_mv_cost_implicit_high_speed;
#else
s_subpel_prms.pf_mv_cost_compute = compute_mv_cost_implicit_high_speed_modified;
#endif
s_subpel_prms.e_me_quality_presets = e_me_quality_presets;
/* BI Refinement done only if this field is 1 */
s_subpel_prms.bidir_enabled = ps_refine_prms->bidir_enabled;
s_subpel_prms.u1_num_ref = ps_ctxt->num_ref_future + ps_ctxt->num_ref_past;
s_subpel_prms.i4_num_act_ref_l0 = ps_ctxt->s_frm_prms.u1_num_active_ref_l0;
s_subpel_prms.i4_num_act_ref_l1 = ps_ctxt->s_frm_prms.u1_num_active_ref_l1;
s_subpel_prms.u1_max_num_subpel_refine_centers =
ps_refine_prms->u1_max_num_subpel_refine_centers;
}
/* inter_ctb_prms_t struct initialisation */
{
inter_ctb_prms_t *ps_inter_ctb_prms = &s_common_frm_prms;
hme_subpel_prms_t *ps_subpel_prms = &s_subpel_prms;
ps_inter_ctb_prms->pps_rec_list_l0 = ps_ctxt->ps_hme_ref_map->pps_rec_list_l0;
ps_inter_ctb_prms->pps_rec_list_l1 = ps_ctxt->ps_hme_ref_map->pps_rec_list_l1;
ps_inter_ctb_prms->wpred_log_wdc = ps_ctxt->s_wt_pred.wpred_log_wdc;
ps_inter_ctb_prms->u1_max_tr_depth = ps_thrd_ctxt->s_init_prms.u1_max_tr_depth;
ps_inter_ctb_prms->i1_quality_preset = e_me_quality_presets;
ps_inter_ctb_prms->i4_bidir_enabled = ps_subpel_prms->bidir_enabled;
ps_inter_ctb_prms->i4_inp_stride = ps_subpel_prms->i4_inp_stride;
ps_inter_ctb_prms->u1_num_ref = ps_subpel_prms->u1_num_ref;
ps_inter_ctb_prms->u1_use_satd = ps_subpel_prms->i4_use_satd;
ps_inter_ctb_prms->i4_rec_stride = ps_curr_layer->i4_rec_stride;
ps_inter_ctb_prms->u1_num_active_ref_l0 = ps_ctxt->s_frm_prms.u1_num_active_ref_l0;
ps_inter_ctb_prms->u1_num_active_ref_l1 = ps_ctxt->s_frm_prms.u1_num_active_ref_l1;
ps_inter_ctb_prms->i4_lamda = lambda_recon;
ps_inter_ctb_prms->u1_lamda_qshift = ps_refine_prms->lambda_q_shift;
ps_inter_ctb_prms->i4_qstep_ls8 = ps_ctxt->ps_hme_frm_prms->qstep_ls8;
ps_inter_ctb_prms->pi4_inv_wt = ps_ctxt->s_wt_pred.a_inv_wpred_wt;
ps_inter_ctb_prms->pi1_past_list = ps_ctxt->ai1_past_list;
ps_inter_ctb_prms->pi1_future_list = ps_ctxt->ai1_future_list;
ps_inter_ctb_prms->pu4_src_variance = s_search_prms_blk.au4_src_variance;
ps_inter_ctb_prms->u1_max_2nx2n_tu_recur_cands =
ps_refine_prms->u1_max_2nx2n_tu_recur_cands;
}
for(i = 0; i < MAX_INIT_CANDTS; i++)
{
ps_search_candts[i].ps_search_node = &ps_ctxt->s_init_search_node[i];
ps_search_candts[i].ps_search_node->ps_mv = &ps_ctxt->as_search_cand_mv[i];
INIT_SEARCH_NODE(ps_search_candts[i].ps_search_node, 0);
}
num_act_ref_pics =
ps_ctxt->s_frm_prms.u1_num_active_ref_l0 + ps_ctxt->s_frm_prms.u1_num_active_ref_l1;
if(num_act_ref_pics)
{
hme_search_cand_data_init(
ai4_id_Z,
ai4_id_coloc,
ai4_num_coloc_cands,
au1_search_candidate_list_index,
i4_num_act_ref_l0,
i4_num_act_ref_l1,
ps_ctxt->s_frm_prms.bidir_enabled,
blk_4x4_to_16x16);
}
if(!ps_ctxt->s_frm_prms.bidir_enabled && (i4_num_act_ref_l0 > 1))
{
ps_search_candts[ai4_id_Z[0]].ps_search_node->i1_ref_idx = ps_ctxt->ai1_past_list[0];
ps_search_candts[ai4_id_Z[1]].ps_search_node->i1_ref_idx = ps_ctxt->ai1_past_list[1];
}
else if(!ps_ctxt->s_frm_prms.bidir_enabled && (i4_num_act_ref_l0 == 1))
{
ps_search_candts[ai4_id_Z[0]].ps_search_node->i1_ref_idx = ps_ctxt->ai1_past_list[0];
}
for(i = 0; i < 3; i++)
{
search_node_t *ps_search_node;
ps_search_node = &as_left_neighbours[i];
INIT_SEARCH_NODE(ps_search_node, 0);
ps_search_node = &as_top_neighbours[i];
INIT_SEARCH_NODE(ps_search_node, 0);
}
INIT_SEARCH_NODE(&as_top_neighbours[3], 0);
as_left_neighbours[2].u1_is_avail = 0;
/*************************************************************************/
/* Initialize all the search results structure here. We update all the */
/* search results to default values, and configure things like blk sizes */
/*************************************************************************/
if(num_act_ref_pics)
{
S32 i4_x, i4_y;
/* 16x16 results */
for(i = 0; i < 16; i++)
{
search_results_t *ps_search_results;
S32 pred_lx;
ps_search_results = &ps_ctxt->as_search_results_16x16[i];
i4_x = (S32)gau1_encode_to_raster_x[i];
i4_y = (S32)gau1_encode_to_raster_y[i];
i4_x <<= 4;
i4_y <<= 4;
hme_init_search_results(
ps_search_results,
i4_num_pred_dir,
ps_refine_prms->i4_num_fpel_results,
ps_refine_prms->i4_num_results_per_part,
e_search_blk_size,
i4_x,
i4_y,
&ps_ctxt->au1_is_past[0]);
for(pred_lx = 0; pred_lx < 2; pred_lx++)
{
pred_ctxt_t *ps_pred_ctxt;
ps_pred_ctxt = &ps_search_results->as_pred_ctxt[pred_lx];
hme_init_pred_ctxt_encode(
ps_pred_ctxt,
ps_search_results,
ps_search_candts[ai4_id_coloc[0]].ps_search_node,
ps_search_candts[ai4_id_Z[0]].ps_search_node,
aps_mv_grid[pred_lx],
pred_lx,
lambda_recon,
ps_refine_prms->lambda_q_shift,
&ps_ctxt->apu1_ref_bits_tlu_lc[0],
&ps_ctxt->ai2_ref_scf[0]);
}
}
for(i = 0; i < 4; i++)
{
search_results_t *ps_search_results;
S32 pred_lx;
ps_search_results = &ps_ctxt->as_search_results_32x32[i];
i4_x = (S32)gau1_encode_to_raster_x[i];
i4_y = (S32)gau1_encode_to_raster_y[i];
i4_x <<= 5;
i4_y <<= 5;
hme_init_search_results(
ps_search_results,
i4_num_pred_dir,
ps_refine_prms->i4_num_32x32_merge_results,
ps_refine_prms->i4_num_results_per_part,
BLK_32x32,
i4_x,
i4_y,
&ps_ctxt->au1_is_past[0]);
for(pred_lx = 0; pred_lx < 2; pred_lx++)
{
pred_ctxt_t *ps_pred_ctxt;
ps_pred_ctxt = &ps_search_results->as_pred_ctxt[pred_lx];
hme_init_pred_ctxt_encode(
ps_pred_ctxt,
ps_search_results,
ps_search_candts[ai4_id_coloc[0]].ps_search_node,
ps_search_candts[ai4_id_Z[0]].ps_search_node,
aps_mv_grid[pred_lx],
pred_lx,
lambda_recon,
ps_refine_prms->lambda_q_shift,
&ps_ctxt->apu1_ref_bits_tlu_lc[0],
&ps_ctxt->ai2_ref_scf[0]);
}
}
{
search_results_t *ps_search_results;
S32 pred_lx;
ps_search_results = &ps_ctxt->s_search_results_64x64;
hme_init_search_results(
ps_search_results,
i4_num_pred_dir,
ps_refine_prms->i4_num_64x64_merge_results,
ps_refine_prms->i4_num_results_per_part,
BLK_64x64,
0,
0,
&ps_ctxt->au1_is_past[0]);
for(pred_lx = 0; pred_lx < 2; pred_lx++)
{
pred_ctxt_t *ps_pred_ctxt;
ps_pred_ctxt = &ps_search_results->as_pred_ctxt[pred_lx];
hme_init_pred_ctxt_encode(
ps_pred_ctxt,
ps_search_results,
ps_search_candts[ai4_id_coloc[0]].ps_search_node,
ps_search_candts[ai4_id_Z[0]].ps_search_node,
aps_mv_grid[pred_lx],
pred_lx,
lambda_recon,
ps_refine_prms->lambda_q_shift,
&ps_ctxt->apu1_ref_bits_tlu_lc[0],
&ps_ctxt->ai2_ref_scf[0]);
}
}
}
/* Initialise the structure used in clustering */
if(ME_PRISTINE_QUALITY == e_me_quality_presets)
{
ps_ctb_cluster_info = ps_ctxt->ps_ctb_cluster_info;
ps_ctb_cluster_info->ps_16x16_blk = ps_ctxt->ps_blk_16x16;
ps_ctb_cluster_info->ps_32x32_blk = ps_ctxt->ps_blk_32x32;
ps_ctb_cluster_info->ps_64x64_blk = ps_ctxt->ps_blk_64x64;
ps_ctb_cluster_info->pi4_blk_8x8_mask = ai4_blk_8x8_mask;
ps_ctb_cluster_info->sdi_threshold = ps_refine_prms->sdi_threshold;
ps_ctb_cluster_info->i4_frame_qstep = ps_ctxt->frm_qstep;
ps_ctb_cluster_info->i4_frame_qstep_multiplier = 16;
}
/*********************************************************************/
/* Initialize the dyn. search range params. for each reference index */
/* in current layer ctxt */
/*********************************************************************/
/* Only for P pic. For P, both are 0, I&B has them mut. exclusive */
if(ps_ctxt->s_frm_prms.is_i_pic == ps_ctxt->s_frm_prms.bidir_enabled)
{
WORD32 ref_ctr;
/* set no. of act ref in L0 for further use at frame level */
ps_ctxt->as_l0_dyn_range_prms[i4_idx_dvsr_p].i4_num_act_ref_in_l0 =
ps_ctxt->s_frm_prms.u1_num_active_ref_l0;
for(ref_ctr = 0; ref_ctr < ps_ctxt->s_frm_prms.u1_num_active_ref_l0; ref_ctr++)
{
INIT_DYN_SEARCH_PRMS(
&ps_ctxt->as_l0_dyn_range_prms[i4_idx_dvsr_p].as_dyn_range_prms[ref_ctr],
ps_ctxt->ai4_ref_idx_to_poc_lc[ref_ctr]);
}
}
/*************************************************************************/
/* Now that the candidates have been ordered, to choose the right number */
/* of initial candidates. */
/*************************************************************************/
if(blk_4x4_to_16x16)
{
if(i4_num_ref_prev_layer > 2)
{
if(e_search_complexity == SEARCH_CX_LOW)
num_init_candts = 7 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else if(e_search_complexity == SEARCH_CX_MED)
num_init_candts = 14 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else if(e_search_complexity == SEARCH_CX_HIGH)
num_init_candts = 21 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else
ASSERT(0);
}
else if(i4_num_ref_prev_layer == 2)
{
if(e_search_complexity == SEARCH_CX_LOW)
num_init_candts = 5 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else if(e_search_complexity == SEARCH_CX_MED)
num_init_candts = 12 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else if(e_search_complexity == SEARCH_CX_HIGH)
num_init_candts = 19 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else
ASSERT(0);
}
else
{
if(e_search_complexity == SEARCH_CX_LOW)
num_init_candts = 5;
else if(e_search_complexity == SEARCH_CX_MED)
num_init_candts = 12;
else if(e_search_complexity == SEARCH_CX_HIGH)
num_init_candts = 19;
else
ASSERT(0);
}
}
else
{
if(i4_num_ref_prev_layer > 2)
{
if(e_search_complexity == SEARCH_CX_LOW)
num_init_candts = 7 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else if(e_search_complexity == SEARCH_CX_MED)
num_init_candts = 13 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else if(e_search_complexity == SEARCH_CX_HIGH)
num_init_candts = 18 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else
ASSERT(0);
}
else if(i4_num_ref_prev_layer == 2)
{
if(e_search_complexity == SEARCH_CX_LOW)
num_init_candts = 5 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else if(e_search_complexity == SEARCH_CX_MED)
num_init_candts = 11 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else if(e_search_complexity == SEARCH_CX_HIGH)
num_init_candts = 16 * (!ps_ctxt->s_frm_prms.bidir_enabled + 1);
else
ASSERT(0);
}
else
{
if(e_search_complexity == SEARCH_CX_LOW)
num_init_candts = 5;
else if(e_search_complexity == SEARCH_CX_MED)
num_init_candts = 11;
else if(e_search_complexity == SEARCH_CX_HIGH)
num_init_candts = 16;
else
ASSERT(0);
}
}
/*************************************************************************/
/* The following search parameters are fixed throughout the search across*/
/* all blks. So these are configured outside processing loop */
/*************************************************************************/
s_search_prms_blk.i4_num_init_candts = num_init_candts;
s_search_prms_blk.i4_start_step = 1;
s_search_prms_blk.i4_use_satd = 0;
s_search_prms_blk.i4_num_steps_post_refine = ps_refine_prms->i4_num_steps_post_refine_fpel;
/* we use recon only for encoded layers, otherwise it is not available */
s_search_prms_blk.i4_use_rec = ps_refine_prms->i4_encode & ps_refine_prms->i4_use_rec_in_fpel;
s_search_prms_blk.ps_search_candts = ps_search_candts;
if(s_search_prms_blk.i4_use_rec)
{
WORD32 ref_ctr;
for(ref_ctr = 0; ref_ctr < MAX_NUM_REF; ref_ctr++)
s_search_prms_blk.aps_mv_range[ref_ctr] = &as_range_prms_rec[ref_ctr];
}
else
{
WORD32 ref_ctr;
for(ref_ctr = 0; ref_ctr < MAX_NUM_REF; ref_ctr++)
s_search_prms_blk.aps_mv_range[ref_ctr] = &as_range_prms_inp[ref_ctr];
}
/*************************************************************************/
/* Initialize coordinates. Meaning as follows */
/* blk_x : x coordinate of the 16x16 blk, in terms of number of blks */
/* blk_y : same as above, y coord. */
/* num_blks_in_this_ctb : number of blks in this given ctb that starts */
/* at i4_ctb_x, i4_ctb_y. This may not be 16 at picture boundaries. */
/* i4_ctb_x, i4_ctb_y: pixel coordinate of the ctb realtive to top left */
/* corner of the picture. Always multiple of 64. */
/* blk_id_in_ctb : encode order id of the blk in the ctb. */
/*************************************************************************/
blk_y = 0;
blk_id_in_ctb = 0;
i4_ctb_y = 0;
/*************************************************************************/
/* Picture limit on all 4 sides. This will be used to set mv limits for */
/* every block given its coordinate. Note thsi assumes that the min amt */
/* of padding to right of pic is equal to the blk size. If we go all the */
/* way upto 64x64, then the min padding on right size of picture should */
/* be 64, and also on bottom side of picture. */
/*************************************************************************/
SET_PIC_LIMIT(
s_pic_limit_inp,
ps_curr_layer->i4_pad_x_rec,
ps_curr_layer->i4_pad_y_rec,
ps_curr_layer->i4_wd,
ps_curr_layer->i4_ht,
s_search_prms_blk.i4_num_steps_post_refine);
SET_PIC_LIMIT(
s_pic_limit_rec,
ps_curr_layer->i4_pad_x_rec,
ps_curr_layer->i4_pad_y_rec,
ps_curr_layer->i4_wd,
ps_curr_layer->i4_ht,
s_search_prms_blk.i4_num_steps_post_refine);
/*************************************************************************/
/* set the MV limit per ref. pic. */
/* - P pic. : Based on the config params. */
/* - B/b pic: Based on the Max/Min MV from prev. P and config. param. */
/*************************************************************************/
hme_set_mv_limit_using_dvsr_data(
ps_ctxt, ps_curr_layer, as_mv_limit, &i2_prev_enc_frm_max_mv_y, num_act_ref_pics);
s_srch_cand_init_data.pu1_num_fpel_search_cands = ps_refine_prms->au1_num_fpel_search_cands;
s_srch_cand_init_data.i4_num_act_ref_l0 = ps_ctxt->s_frm_prms.u1_num_active_ref_l0;
s_srch_cand_init_data.i4_num_act_ref_l1 = ps_ctxt->s_frm_prms.u1_num_active_ref_l1;
s_srch_cand_init_data.ps_coarse_layer = ps_coarse_layer;
s_srch_cand_init_data.ps_curr_layer = ps_curr_layer;
s_srch_cand_init_data.i4_max_num_init_cands = num_init_candts;
s_srch_cand_init_data.ps_search_cands = ps_search_candts;
s_srch_cand_init_data.u1_num_results_in_mvbank = s_mv_update_prms.i4_num_results_to_store;
s_srch_cand_init_data.pi4_ref_id_lc_to_l0_map = ps_ctxt->a_ref_idx_lc_to_l0;
s_srch_cand_init_data.pi4_ref_id_lc_to_l1_map = ps_ctxt->a_ref_idx_lc_to_l1;
s_srch_cand_init_data.e_search_blk_size = e_search_blk_size;
while(0 == end_of_frame)
{
job_queue_t *ps_job;
frm_ctb_ctxt_t *ps_frm_ctb_prms;
ipe_l0_ctb_analyse_for_me_t *ps_cur_ipe_ctb;
WORD32 i4_max_mv_x_in_ctb;
WORD32 i4_max_mv_y_in_ctb;
void *pv_dep_mngr_encloop_dep_me;
WORD32 offset_val, check_dep_pos, set_dep_pos;
WORD32 left_ctb_in_diff_tile, i4_first_ctb_x = 0;
pv_dep_mngr_encloop_dep_me = ps_ctxt->pv_dep_mngr_encloop_dep_me;
ps_frm_ctb_prms = (frm_ctb_ctxt_t *)ps_thrd_ctxt->pv_ext_frm_prms;
/* Get the current row from the job queue */
ps_job = (job_queue_t *)ihevce_enc_grp_get_next_job(
ps_multi_thrd_ctxt, lyr_job_type, 1, me_frm_id);
/* If all rows are done, set the end of process flag to 1, */
/* and the current row to -1 */
if(NULL == ps_job)
{
blk_y = -1;
i4_ctb_y = -1;
tile_col_idx = -1;
end_of_frame = 1;
continue;
}
/* set the output dependency after picking up the row */
ihevce_enc_grp_job_set_out_dep(ps_multi_thrd_ctxt, ps_job, me_frm_id);
/* Obtain the current row's details from the job */
{
ihevce_tile_params_t *ps_col_tile_params;
i4_ctb_y = ps_job->s_job_info.s_me_job_info.i4_vert_unit_row_no;
/* Obtain the current colum tile index from the job */
tile_col_idx = ps_job->s_job_info.s_me_job_info.i4_tile_col_idx;
/* in encode layer block are 16x16 and CTB is 64 x 64 */
/* note if ctb is 32x32 the this calc needs to be changed */
num_sync_units_in_row = (i4_pic_wd + ((1 << ps_ctxt->log_ctb_size) - 1)) >>
ps_ctxt->log_ctb_size;
/* The tile parameter for the col. idx. Use only the properties
which is same for all the bottom tiles like width, start_x, etc.
Don't use height, start_y, etc. */
ps_col_tile_params =
((ihevce_tile_params_t *)ps_thrd_ctxt->pv_tile_params_base + tile_col_idx);
/* in encode layer block are 16x16 and CTB is 64 x 64 */
/* note if ctb is 32x32 the this calc needs to be changed */
num_sync_units_in_tile =
(ps_col_tile_params->i4_curr_tile_width + ((1 << ps_ctxt->log_ctb_size) - 1)) >>
ps_ctxt->log_ctb_size;
i4_first_ctb_x = ps_col_tile_params->i4_first_ctb_x;
i4_ctb_x = i4_first_ctb_x;
if(!num_act_ref_pics)
{
for(i4_ctb_x = i4_first_ctb_x;
i4_ctb_x < (ps_col_tile_params->i4_first_ctb_x + num_sync_units_in_tile);
i4_ctb_x++)
{
S32 blk_i = 0, blk_j = 0;
/* set the dependency for the corresponding row in enc loop */
ihevce_dmgr_set_row_row_sync(
pv_dep_mngr_encloop_dep_me,
(i4_ctb_x + 1),
i4_ctb_y,
tile_col_idx /* Col Tile No. */);
}
continue;
}
/* increment the number of rows proc */
num_rows_proc++;
/* Set Variables for Dep. Checking and Setting */
set_dep_pos = i4_ctb_y + 1;
if(i4_ctb_y > 0)
{
offset_val = 2;
check_dep_pos = i4_ctb_y - 1;
}
else
{
/* First row should run without waiting */
offset_val = -1;
check_dep_pos = 0;
}
/* row ctb out pointer */
ps_ctxt->ps_ctb_analyse_curr_row =
ps_ctxt->ps_ctb_analyse_base + i4_ctb_y * ps_frm_ctb_prms->i4_num_ctbs_horz;
/* Row level CU Tree buffer */
ps_ctxt->ps_cu_tree_curr_row =
ps_ctxt->ps_cu_tree_base +
i4_ctb_y * ps_frm_ctb_prms->i4_num_ctbs_horz * MAX_NUM_NODES_CU_TREE;
ps_ctxt->ps_me_ctb_data_curr_row =
ps_ctxt->ps_me_ctb_data_base + i4_ctb_y * ps_frm_ctb_prms->i4_num_ctbs_horz;
}
/* This flag says the CTB under processing is at the start of tile in horz dir.*/
left_ctb_in_diff_tile = 1;
/* To make sure no 64-bit overflow happens when inv_wt is multiplied with un-normalized src_var, */
/* the shift value will be passed onto the functions wherever inv_wt isused so that inv_wt is appropriately shift and multiplied */
{
S32 i4_ref_id, i4_bits_req;
for(i4_ref_id = 0; i4_ref_id < (ps_ctxt->s_frm_prms.u1_num_active_ref_l0 +
ps_ctxt->s_frm_prms.u1_num_active_ref_l1);
i4_ref_id++)
{
GETRANGE(i4_bits_req, ps_ctxt->s_wt_pred.a_inv_wpred_wt[i4_ref_id]);
if(i4_bits_req > 12)
{
ps_ctxt->s_wt_pred.ai4_shift_val[i4_ref_id] = (i4_bits_req - 12);
}
else
{
ps_ctxt->s_wt_pred.ai4_shift_val[i4_ref_id] = 0;
}
}
s_common_frm_prms.pi4_inv_wt_shift_val = ps_ctxt->s_wt_pred.ai4_shift_val;
}
/* if non-encode layer then i4_ctb_x will be same as blk_x */
/* loop over all the units is a row */
for(i4_ctb_x = i4_first_ctb_x; i4_ctb_x < (i4_first_ctb_x + num_sync_units_in_tile);
i4_ctb_x++)
{
ihevce_ctb_noise_params *ps_ctb_noise_params =
&ps_ctxt->ps_ctb_analyse_curr_row[i4_ctb_x].s_ctb_noise_params;
s_common_frm_prms.i4_ctb_x_off = i4_ctb_x << 6;
s_common_frm_prms.i4_ctb_y_off = i4_ctb_y << 6;
ps_ctxt->s_mc_ctxt.i4_ctb_frm_pos_y = i4_ctb_y << 6;
ps_ctxt->s_mc_ctxt.i4_ctb_frm_pos_x = i4_ctb_x << 6;
/* Initialize ptr to current IPE CTB */
ps_cur_ipe_ctb = ps_ctxt->ps_ipe_l0_ctb_frm_base + i4_ctb_x +
i4_ctb_y * ps_frm_ctb_prms->i4_num_ctbs_horz;
{
ps_ctb_bound_attrs =
get_ctb_attrs(i4_ctb_x << 6, i4_ctb_y << 6, i4_pic_wd, i4_pic_ht, ps_ctxt);
en_merge_32x32 = ps_ctb_bound_attrs->u1_merge_to_32x32_flag;
num_blks_in_this_ctb = ps_ctb_bound_attrs->u1_num_blks_in_ctb;
}
/* Block to initialise pointers to part_type_results_t */
/* in each size-specific inter_cu_results_t */
{
WORD32 i;
for(i = 0; i < 64; i++)
{
ps_ctxt->as_cu8x8_results[i].ps_best_results =
ps_ctxt->ps_me_ctb_data_curr_row[i4_ctb_x]
.as_8x8_block_data[i]
.as_best_results;
ps_ctxt->as_cu8x8_results[i].u1_num_best_results = 0;
}
for(i = 0; i < 16; i++)
{
ps_ctxt->as_cu16x16_results[i].ps_best_results =
ps_ctxt->ps_me_ctb_data_curr_row[i4_ctb_x].as_block_data[i].as_best_results;
ps_ctxt->as_cu16x16_results[i].u1_num_best_results = 0;
}
for(i = 0; i < 4; i++)
{
ps_ctxt->as_cu32x32_results[i].ps_best_results =
ps_ctxt->ps_me_ctb_data_curr_row[i4_ctb_x]
.as_32x32_block_data[i]
.as_best_results;
ps_ctxt->as_cu32x32_results[i].u1_num_best_results = 0;
}
ps_ctxt->s_cu64x64_results.ps_best_results =
ps_ctxt->ps_me_ctb_data_curr_row[i4_ctb_x].s_64x64_block_data.as_best_results;
ps_ctxt->s_cu64x64_results.u1_num_best_results = 0;
}
if(ME_PRISTINE_QUALITY == e_me_quality_presets)
{
ps_ctb_cluster_info->blk_32x32_mask = en_merge_32x32;
ps_ctb_cluster_info->ps_cur_ipe_ctb = ps_cur_ipe_ctb;
ps_ctb_cluster_info->ps_cu_tree_root =
ps_ctxt->ps_cu_tree_curr_row + (i4_ctb_x * MAX_NUM_NODES_CU_TREE);
ps_ctb_cluster_info->nodes_created_in_cu_tree = 1;
}
if(ME_PRISTINE_QUALITY != e_me_quality_presets)
{
S32 i4_nodes_created_in_cu_tree = 1;
ihevce_cu_tree_init(
(ps_ctxt->ps_cu_tree_curr_row + (i4_ctb_x * MAX_NUM_NODES_CU_TREE)),
(ps_ctxt->ps_cu_tree_curr_row + (i4_ctb_x * MAX_NUM_NODES_CU_TREE)),
&i4_nodes_created_in_cu_tree,
0,
POS_NA,
POS_NA,
POS_NA);
}
memset(ai4_blk_8x8_mask, 0, 16 * sizeof(S32));
if(ps_refine_prms->u1_use_lambda_derived_from_min_8x8_act_in_ctb)
{
S32 j;
ipe_l0_ctb_analyse_for_me_t *ps_cur_ipe_ctb;
ps_cur_ipe_ctb =
ps_ctxt->ps_ipe_l0_ctb_frm_base + i4_ctb_x + i4_ctb_y * num_sync_units_in_row;
lambda_recon =
hme_recompute_lambda_from_min_8x8_act_in_ctb(ps_ctxt, ps_cur_ipe_ctb);
lambda_recon = ((float)lambda_recon * (100.0f - ME_LAMBDA_DISCOUNT) / 100.0f);
for(i = 0; i < 4; i++)
{
ps_search_results = &ps_ctxt->as_search_results_32x32[i];
for(j = 0; j < 2; j++)
{
ps_search_results->as_pred_ctxt[j].lambda = lambda_recon;
}
}
ps_search_results = &ps_ctxt->s_search_results_64x64;
for(j = 0; j < 2; j++)
{
ps_search_results->as_pred_ctxt[j].lambda = lambda_recon;
}
s_common_frm_prms.i4_lamda = lambda_recon;
}
else
{
lambda_recon = ps_refine_prms->lambda_recon;
}
/*********************************************************************/
/* replicate the inp buffer at blk or ctb level for each ref id, */
/* Instead of searching with wk * ref(k), we search with Ik = I / wk */
/* thereby avoiding a bloat up of memory. If we did all references */
/* weighted pred, we will end up with a duplicate copy of each ref */
/* at each layer, since we need to preserve the original reference. */
/* ToDo: Need to observe performance with this mechanism and compare */
/* with case where ref is weighted. */
/*********************************************************************/
fp_get_wt_inp(
ps_curr_layer,
&ps_ctxt->s_wt_pred,
unit_size,
s_common_frm_prms.i4_ctb_x_off,
s_common_frm_prms.i4_ctb_y_off,
unit_size,
ps_ctxt->num_ref_future + ps_ctxt->num_ref_past,
ps_ctxt->i4_wt_pred_enable_flag);
if(ps_thrd_ctxt->s_init_prms.u1_is_stasino_enabled)
{
#if TEMPORAL_NOISE_DETECT
{
WORD32 had_block_size = 16;
WORD32 ctb_width = ((i4_pic_wd - s_common_frm_prms.i4_ctb_x_off) >= 64)
? 64
: i4_pic_wd - s_common_frm_prms.i4_ctb_x_off;
WORD32 ctb_height = ((i4_pic_ht - s_common_frm_prms.i4_ctb_y_off) >= 64)
? 64
: i4_pic_ht - s_common_frm_prms.i4_ctb_y_off;
WORD32 num_pred_dir = i4_num_pred_dir;
WORD32 i4_x_off = s_common_frm_prms.i4_ctb_x_off;
WORD32 i4_y_off = s_common_frm_prms.i4_ctb_y_off;
WORD32 i;
WORD32 noise_detected;
WORD32 ctb_size;
WORD32 num_comp_had_blocks;
WORD32 noisy_block_cnt;
WORD32 index_8x8_block;
WORD32 num_8x8_in_ctb_row;
WORD32 ht_offset;
WORD32 wd_offset;
WORD32 block_ht;
WORD32 block_wd;
WORD32 num_horz_blocks;
WORD32 num_vert_blocks;
WORD32 mean;
UWORD32 variance_8x8;
WORD32 hh_energy_percent;
/* variables to hold the constant values. The variable values held are decided by the HAD block size */
WORD32 min_noisy_block_cnt;
WORD32 min_coeffs_above_avg;
WORD32 min_coeff_avg_energy;
/* to store the mean and variance of each 8*8 block and find the variance of any higher block sizes later on. block */
WORD32 i4_cu_x_off, i4_cu_y_off;
WORD32 is_noisy;
/* intialise the variables holding the constants */
if(had_block_size == 8)
{
min_noisy_block_cnt = MIN_NOISY_BLOCKS_CNT_8x8; //6;//
min_coeffs_above_avg = MIN_NUM_COEFFS_ABOVE_AVG_8x8;
min_coeff_avg_energy = MIN_COEFF_AVG_ENERGY_8x8;
}
else
{
min_noisy_block_cnt = MIN_NOISY_BLOCKS_CNT_16x16; //7;//
min_coeffs_above_avg = MIN_NUM_COEFFS_ABOVE_AVG_16x16;
min_coeff_avg_energy = MIN_COEFF_AVG_ENERGY_16x16;
}
/* initialize the variables */
noise_detected = 0;
noisy_block_cnt = 0;
hh_energy_percent = 0;
variance_8x8 = 0;
block_ht = ctb_height;
block_wd = ctb_width;
mean = 0;
ctb_size = block_ht * block_wd; //ctb_width * ctb_height;
num_comp_had_blocks = ctb_size / (had_block_size * had_block_size);
num_horz_blocks = block_wd / had_block_size; //ctb_width / had_block_size;
num_vert_blocks = block_ht / had_block_size; //ctb_height / had_block_size;
ht_offset = -had_block_size;
wd_offset = -had_block_size;
num_8x8_in_ctb_row = block_wd / 8; // number of 8x8 in this ctb
for(i = 0; i < num_comp_had_blocks; i++)
{
if(i % num_horz_blocks == 0)
{
wd_offset = -had_block_size;
ht_offset += had_block_size;
}
wd_offset += had_block_size;
/* CU level offsets */
i4_cu_x_off = i4_x_off + (i % 4) * 16; //+ (i % 4) * 16
i4_cu_y_off = i4_y_off + (i / 4) * 16;
/* if 50 % or more of the CU is noisy then the return value is 1 */
is_noisy = ihevce_determine_cu_noise_based_on_8x8Blk_data(
ps_ctb_noise_params->au1_is_8x8Blk_noisy,
(i % 4) * 16,
(i / 4) * 16,
16);
/* only if the CU is noisy then check the temporal noise detect call is made on the CU */
if(is_noisy)
{
index_8x8_block = (i / num_horz_blocks) * 2 * num_8x8_in_ctb_row +
(i % num_horz_blocks) * 2;
noisy_block_cnt += ihevce_16x16block_temporal_noise_detect(
16,
((i4_pic_wd - s_common_frm_prms.i4_ctb_x_off) >= 64)
? 64
: i4_pic_wd - s_common_frm_prms.i4_ctb_x_off,
((i4_pic_ht - s_common_frm_prms.i4_ctb_y_off) >= 64)
? 64
: i4_pic_ht - s_common_frm_prms.i4_ctb_y_off,
ps_ctb_noise_params,
&s_srch_cand_init_data,
&s_search_prms_blk,
ps_ctxt,
num_pred_dir,
i4_num_act_ref_l0,
i4_num_act_ref_l1,
i4_cu_x_off,
i4_cu_y_off,
&ps_ctxt->s_wt_pred,
unit_size,
index_8x8_block,
num_horz_blocks,
/*num_8x8_in_ctb_row*/ 8, // this should be a variable extra
i);
} /* if 16x16 is noisy */
} /* loop over for all 16x16*/
if(noisy_block_cnt >= min_noisy_block_cnt)
{
noise_detected = 1;
}
/* write back the noise presence detected for the current CTB to the structure */
ps_ctb_noise_params->i4_noise_present = noise_detected;
}
#endif
#if EVERYWHERE_NOISY && USE_NOISE_TERM_IN_L0_ME
if(ps_thrd_ctxt->s_init_prms.u1_is_stasino_enabled &&
ps_ctb_noise_params->i4_noise_present)
{
memset(
ps_ctb_noise_params->au1_is_8x8Blk_noisy,
1,
sizeof(ps_ctb_noise_params->au1_is_8x8Blk_noisy));
}
#endif
for(i = 0; i < 16; i++)
{
au1_is_16x16Blk_noisy[i] = ihevce_determine_cu_noise_based_on_8x8Blk_data(
ps_ctb_noise_params->au1_is_8x8Blk_noisy, (i % 4) * 16, (i / 4) * 16, 16);
}
for(i = 0; i < 4; i++)
{
au1_is_32x32Blk_noisy[i] = ihevce_determine_cu_noise_based_on_8x8Blk_data(
ps_ctb_noise_params->au1_is_8x8Blk_noisy, (i % 2) * 32, (i / 2) * 32, 32);
}
for(i = 0; i < 1; i++)
{
au1_is_64x64Blk_noisy[i] = ihevce_determine_cu_noise_based_on_8x8Blk_data(
ps_ctb_noise_params->au1_is_8x8Blk_noisy, 0, 0, 64);
}
if(ps_ctxt->s_frm_prms.bidir_enabled &&
(ps_ctxt->s_frm_prms.i4_temporal_layer_id <=
MAX_LAYER_ID_OF_B_PICS_WITHOUT_NOISE_DETECTION))
{
ps_ctb_noise_params->i4_noise_present = 0;
memset(
ps_ctb_noise_params->au1_is_8x8Blk_noisy,
0,
sizeof(ps_ctb_noise_params->au1_is_8x8Blk_noisy));
}
#if ME_LAMBDA_DISCOUNT_WHEN_NOISY
for(i = 0; i < 4; i++)
{
S32 j;
S32 lambda;
if(au1_is_32x32Blk_noisy[i])
{
lambda = lambda_recon;
lambda =
((float)lambda * (100.0f - ME_LAMBDA_DISCOUNT_WHEN_NOISY) / 100.0f);
ps_search_results = &ps_ctxt->as_search_results_32x32[i];
for(j = 0; j < 2; j++)
{
ps_search_results->as_pred_ctxt[j].lambda = lambda;
}
}
}
{
S32 j;
S32 lambda;
if(au1_is_64x64Blk_noisy[0])
{
lambda = lambda_recon;
lambda =
((float)lambda * (100.0f - ME_LAMBDA_DISCOUNT_WHEN_NOISY) / 100.0f);
ps_search_results = &ps_ctxt->s_search_results_64x64;
for(j = 0; j < 2; j++)
{
ps_search_results->as_pred_ctxt[j].lambda = lambda;
}
}
}
#endif
if(au1_is_64x64Blk_noisy[0])
{
U08 *pu1_inp = ps_curr_layer->pu1_inp + (s_common_frm_prms.i4_ctb_x_off +
(s_common_frm_prms.i4_ctb_y_off *
ps_curr_layer->i4_inp_stride));
hme_compute_sigmaX_and_sigmaXSquared(
pu1_inp,
ps_curr_layer->i4_inp_stride,
ps_ctxt->au4_4x4_src_sigmaX,
ps_ctxt->au4_4x4_src_sigmaXSquared,
4,
4,
64,
64,
1,
16);
}
else
{
for(i = 0; i < 4; i++)
{
if(au1_is_32x32Blk_noisy[i])
{
U08 *pu1_inp =
ps_curr_layer->pu1_inp +
(s_common_frm_prms.i4_ctb_x_off +
(s_common_frm_prms.i4_ctb_y_off * ps_curr_layer->i4_inp_stride));
U08 u1_cu_size = 32;
WORD32 i4_inp_buf_offset =
(((i / 2) * (u1_cu_size * ps_curr_layer->i4_inp_stride)) +
((i % 2) * u1_cu_size));
U16 u2_sigma_arr_start_index_of_3rd_32x32_blk_in_ctb = 128;
U16 u2_sigma_arr_start_index_of_2nd_32x32_blk_in_ctb = 8;
S32 i4_sigma_arr_offset =
(((i / 2) * u2_sigma_arr_start_index_of_3rd_32x32_blk_in_ctb) +
((i % 2) * u2_sigma_arr_start_index_of_2nd_32x32_blk_in_ctb));
hme_compute_sigmaX_and_sigmaXSquared(
pu1_inp + i4_inp_buf_offset,
ps_curr_layer->i4_inp_stride,
ps_ctxt->au4_4x4_src_sigmaX + i4_sigma_arr_offset,
ps_ctxt->au4_4x4_src_sigmaXSquared + i4_sigma_arr_offset,
4,
4,
32,
32,
1,
16);
}
else
{
S32 j;
U08 u1_16x16_blk_start_index_in_3rd_32x32_blk_of_ctb = 8;
U08 u1_16x16_blk_start_index_in_2nd_32x32_blk_of_ctb = 2;
S32 i4_16x16_blk_start_index_in_i_th_32x32_blk =
(((i / 2) * u1_16x16_blk_start_index_in_3rd_32x32_blk_of_ctb) +
((i % 2) * u1_16x16_blk_start_index_in_2nd_32x32_blk_of_ctb));
for(j = 0; j < 4; j++)
{
U08 u1_3rd_16x16_blk_index_in_32x32_blk = 4;
U08 u1_2nd_16x16_blk_index_in_32x32_blk = 1;
S32 i4_16x16_blk_index_in_ctb =
i4_16x16_blk_start_index_in_i_th_32x32_blk +
((j % 2) * u1_2nd_16x16_blk_index_in_32x32_blk) +
((j / 2) * u1_3rd_16x16_blk_index_in_32x32_blk);
//S32 k = (((i / 2) * 8) + ((i % 2) * 2)) + ((j % 2) * 1) + ((j / 2) * 4);
if(au1_is_16x16Blk_noisy[i4_16x16_blk_index_in_ctb])
{
U08 *pu1_inp =
ps_curr_layer->pu1_inp + (s_common_frm_prms.i4_ctb_x_off +
(s_common_frm_prms.i4_ctb_y_off *
ps_curr_layer->i4_inp_stride));
U08 u1_cu_size = 16;
WORD32 i4_inp_buf_offset =
(((i4_16x16_blk_index_in_ctb % 4) * u1_cu_size) +
((i4_16x16_blk_index_in_ctb / 4) *
(u1_cu_size * ps_curr_layer->i4_inp_stride)));
U16 u2_sigma_arr_start_index_of_3rd_16x16_blk_in_32x32_blk = 64;
U16 u2_sigma_arr_start_index_of_2nd_16x16_blk_in_32x32_blk = 4;
S32 i4_sigma_arr_offset =
(((i4_16x16_blk_index_in_ctb % 4) *
u2_sigma_arr_start_index_of_2nd_16x16_blk_in_32x32_blk) +
((i4_16x16_blk_index_in_ctb / 4) *
u2_sigma_arr_start_index_of_3rd_16x16_blk_in_32x32_blk));
hme_compute_sigmaX_and_sigmaXSquared(
pu1_inp + i4_inp_buf_offset,
ps_curr_layer->i4_inp_stride,
(ps_ctxt->au4_4x4_src_sigmaX + i4_sigma_arr_offset),
(ps_ctxt->au4_4x4_src_sigmaXSquared + i4_sigma_arr_offset),
4,
4,
16,
16,
1,
16);
}
}
}
}
}
}
else
{
memset(au1_is_16x16Blk_noisy, 0, sizeof(au1_is_16x16Blk_noisy));
memset(au1_is_32x32Blk_noisy, 0, sizeof(au1_is_32x32Blk_noisy));
memset(au1_is_64x64Blk_noisy, 0, sizeof(au1_is_64x64Blk_noisy));
}
for(blk_id_in_ctb = 0; blk_id_in_ctb < num_blks_in_this_ctb; blk_id_in_ctb++)
{
S32 ref_ctr;
U08 au1_pred_dir_searched[2];
U08 u1_is_cu_noisy;
ULWORD64 au8_final_src_sigmaX[17], au8_final_src_sigmaXSquared[17];
{
blk_x = (i4_ctb_x << 2) +
(ps_ctb_bound_attrs->as_blk_attrs[blk_id_in_ctb].u1_blk_x);
blk_y = (i4_ctb_y << 2) +
(ps_ctb_bound_attrs->as_blk_attrs[blk_id_in_ctb].u1_blk_y);
blk_id_in_full_ctb =
ps_ctb_bound_attrs->as_blk_attrs[blk_id_in_ctb].u1_blk_id_in_full_ctb;
blk_8x8_mask = ps_ctb_bound_attrs->as_blk_attrs[blk_id_in_ctb].u1_blk_8x8_mask;
ai4_blk_8x8_mask[blk_id_in_full_ctb] = blk_8x8_mask;
s_search_prms_blk.i4_cu_x_off = (blk_x << blk_size_shift) - (i4_ctb_x << 6);
s_search_prms_blk.i4_cu_y_off = (blk_y << blk_size_shift) - (i4_ctb_y << 6);
}
/* get the current input blk point */
pos_x = blk_x << blk_size_shift;
pos_y = blk_y << blk_size_shift;
pu1_inp = ps_curr_layer->pu1_inp + pos_x + (pos_y * i4_inp_stride);
/*********************************************************************/
/* For every blk in the picture, the search range needs to be derived*/
/* Any blk can have any mv, but practical search constraints are */
/* imposed by the picture boundary and amt of padding. */
/*********************************************************************/
/* MV limit is different based on ref. PIC */
for(ref_ctr = 0; ref_ctr < num_act_ref_pics; ref_ctr++)
{
if(!s_search_prms_blk.i4_use_rec)
{
hme_derive_search_range(
&as_range_prms_inp[ref_ctr],
&s_pic_limit_inp,
&as_mv_limit[ref_ctr],
pos_x,
pos_y,
blk_wd,
blk_ht);
}
else
{
hme_derive_search_range(
&as_range_prms_rec[ref_ctr],
&s_pic_limit_rec,
&as_mv_limit[ref_ctr],
pos_x,
pos_y,
blk_wd,
blk_ht);
}
}
s_search_prms_blk.i4_x_off = blk_x << blk_size_shift;
s_search_prms_blk.i4_y_off = blk_y << blk_size_shift;
/* Select search results from a suitable search result in the context */
{
ps_search_results = &ps_ctxt->as_search_results_16x16[blk_id_in_full_ctb];
if(ps_refine_prms->u1_use_lambda_derived_from_min_8x8_act_in_ctb)
{
S32 i;
for(i = 0; i < 2; i++)
{
ps_search_results->as_pred_ctxt[i].lambda = lambda_recon;
}
}
}
u1_is_cu_noisy = au1_is_16x16Blk_noisy
[(s_search_prms_blk.i4_cu_x_off >> 4) + (s_search_prms_blk.i4_cu_y_off >> 2)];
s_subpel_prms.u1_is_cu_noisy = u1_is_cu_noisy;
#if ME_LAMBDA_DISCOUNT_WHEN_NOISY
if(u1_is_cu_noisy)
{
S32 j;
S32 lambda;
lambda = lambda_recon;
lambda = ((float)lambda * (100.0f - ME_LAMBDA_DISCOUNT_WHEN_NOISY) / 100.0f);
for(j = 0; j < 2; j++)
{
ps_search_results->as_pred_ctxt[j].lambda = lambda;
}
}
else
{
S32 j;
S32 lambda;
lambda = lambda_recon;
for(j = 0; j < 2; j++)
{
ps_search_results->as_pred_ctxt[j].lambda = lambda;
}
}
#endif
s_search_prms_blk.ps_search_results = ps_search_results;
s_search_prms_blk.i4_part_mask = hme_part_mask_populator(
pu1_inp,
i4_inp_stride,
ps_refine_prms->limit_active_partitions,
ps_ctxt->ps_hme_frm_prms->bidir_enabled,
ps_ctxt->u1_is_curFrame_a_refFrame,
blk_8x8_mask,
e_me_quality_presets);
if(ME_PRISTINE_QUALITY == e_me_quality_presets)
{
ps_ctb_cluster_info->ai4_part_mask[blk_id_in_full_ctb] =
s_search_prms_blk.i4_part_mask;
}
/* RESET ALL SEARCH RESULTS FOR THE NEW BLK */
{
/* Setting u1_num_active_refs to 2 */
/* for the sole purpose of the */
/* function called below */
ps_search_results->u1_num_active_ref = (ps_refine_prms->bidir_enabled) ? 2 : 1;
hme_reset_search_results(
ps_search_results, s_search_prms_blk.i4_part_mask, MV_RES_FPEL);
ps_search_results->u1_num_active_ref = i4_num_pred_dir;
}
if(0 == blk_id_in_ctb)
{
UWORD8 u1_ctr;
for(u1_ctr = 0; u1_ctr < (ps_ctxt->s_frm_prms.u1_num_active_ref_l0 +
ps_ctxt->s_frm_prms.u1_num_active_ref_l1);
u1_ctr++)
{
WORD32 i4_max_dep_ctb_y;
WORD32 i4_max_dep_ctb_x;
/* Set max mv in ctb units */
i4_max_mv_x_in_ctb =
(ps_curr_layer->i2_max_mv_x + ((1 << ps_ctxt->log_ctb_size) - 1)) >>
ps_ctxt->log_ctb_size;
i4_max_mv_y_in_ctb =
(as_mv_limit[u1_ctr].i2_max_y + ((1 << ps_ctxt->log_ctb_size) - 1)) >>
ps_ctxt->log_ctb_size;
/********************************************************************/
/* Set max ctb_x and ctb_y dependency on reference picture */
/* Note +1 is due to delayed deblock, SAO, subpel plan dependency */
/********************************************************************/
i4_max_dep_ctb_x = CLIP3(
(i4_ctb_x + i4_max_mv_x_in_ctb + 1),
0,
ps_frm_ctb_prms->i4_num_ctbs_horz - 1);
i4_max_dep_ctb_y = CLIP3(
(i4_ctb_y + i4_max_mv_y_in_ctb + 1),
0,
ps_frm_ctb_prms->i4_num_ctbs_vert - 1);
ihevce_dmgr_map_chk_sync(
ps_curr_layer->ppv_dep_mngr_recon[u1_ctr],
ps_ctxt->thrd_id,
i4_ctb_x,
i4_ctb_y,
i4_max_mv_x_in_ctb,
i4_max_mv_y_in_ctb);
}
}
/* Loop across different Ref IDx */
for(u1_pred_dir_ctr = 0; u1_pred_dir_ctr < i4_num_pred_dir; u1_pred_dir_ctr++)
{
S32 resultid;
S08 u1_default_ref_id;
S32 i4_num_srch_cands = 0;
S32 i4_num_refinement_iterations;
S32 i4_refine_iter_ctr;
if((i4_num_pred_dir == 2) || (!ps_ctxt->s_frm_prms.bidir_enabled) ||
(ps_ctxt->s_frm_prms.u1_num_active_ref_l1 == 0))
{
u1_pred_dir = u1_pred_dir_ctr;
}
else if(ps_ctxt->s_frm_prms.u1_num_active_ref_l0 == 0)
{
u1_pred_dir = 1;
}
u1_default_ref_id = (u1_pred_dir == 0) ? ps_ctxt->ai1_past_list[0]
: ps_ctxt->ai1_future_list[0];
au1_pred_dir_searched[u1_pred_dir_ctr] = u1_pred_dir;
i4_num_srch_cands = 0;
resultid = 0;
/* START OF NEW CTB MEANS FILL UP NEOGHBOURS IN 18x18 GRID */
if(0 == blk_id_in_ctb)
{
/*****************************************************************/
/* Initialize the mv grid with results of neighbours for the next*/
/* ctb. */
/*****************************************************************/
hme_fill_ctb_neighbour_mvs(
ps_curr_layer,
blk_x,
blk_y,
aps_mv_grid[u1_pred_dir],
u1_pred_dir_ctr,
u1_default_ref_id,
ps_ctxt->s_frm_prms.u1_num_active_ref_l0);
}
s_search_prms_blk.i1_ref_idx = u1_pred_dir;
{
if((blk_id_in_full_ctb % 4) == 0)
{
ps_ctxt->as_search_results_32x32[blk_id_in_full_ctb >> 2]
.as_pred_ctxt[u1_pred_dir]
.proj_used = (blk_id_in_full_ctb == 8) ? 0 : 1;
}
if(blk_id_in_full_ctb == 0)
{
ps_ctxt->s_search_results_64x64.as_pred_ctxt[u1_pred_dir].proj_used = 1;
}
ps_search_results->as_pred_ctxt[u1_pred_dir].proj_used =
!gau1_encode_to_raster_y[blk_id_in_full_ctb];
}
{
S32 x = gau1_encode_to_raster_x[blk_id_in_full_ctb];
S32 y = gau1_encode_to_raster_y[blk_id_in_full_ctb];
U08 u1_is_blk_at_ctb_boundary = !y;
s_srch_cand_init_data.u1_is_left_available =
!(left_ctb_in_diff_tile && !s_search_prms_blk.i4_cu_x_off);
if(u1_is_blk_at_ctb_boundary)
{
s_srch_cand_init_data.u1_is_topRight_available = 0;
s_srch_cand_init_data.u1_is_topLeft_available = 0;
s_srch_cand_init_data.u1_is_top_available = 0;
}
else
{
s_srch_cand_init_data.u1_is_topRight_available =
gau1_cu_tr_valid[y][x] && ((pos_x + blk_wd) < i4_pic_wd);
s_srch_cand_init_data.u1_is_top_available = 1;
s_srch_cand_init_data.u1_is_topLeft_available =
s_srch_cand_init_data.u1_is_left_available;
}
}
s_srch_cand_init_data.i1_default_ref_id = u1_default_ref_id;
s_srch_cand_init_data.i1_alt_default_ref_id = ps_ctxt->ai1_past_list[1];
s_srch_cand_init_data.i4_pos_x = pos_x;
s_srch_cand_init_data.i4_pos_y = pos_y;
s_srch_cand_init_data.u1_pred_dir = u1_pred_dir;
s_srch_cand_init_data.u1_pred_dir_ctr = u1_pred_dir_ctr;
s_srch_cand_init_data.u1_search_candidate_list_index =
au1_search_candidate_list_index[u1_pred_dir];
i4_num_srch_cands = hme_populate_search_candidates(&s_srch_cand_init_data);
/* Note this block also clips the MV range for all candidates */
{
S08 i1_check_for_mult_refs;
i1_check_for_mult_refs = u1_pred_dir ? (ps_ctxt->num_ref_future > 1)
: (ps_ctxt->num_ref_past > 1);
ps_me_optimised_function_list->pf_mv_clipper(
&s_search_prms_blk,
i4_num_srch_cands,
i1_check_for_mult_refs,
ps_refine_prms->i4_num_steps_fpel_refine,
ps_refine_prms->i4_num_steps_hpel_refine,
ps_refine_prms->i4_num_steps_qpel_refine);
}
#if ENABLE_EXPLICIT_SEARCH_IN_P_IN_L0
i4_num_refinement_iterations =
((!ps_ctxt->s_frm_prms.bidir_enabled) && (i4_num_act_ref_l0 > 1))
? ((e_me_quality_presets == ME_HIGH_QUALITY) ? 2 : i4_num_act_ref_l0)
: 1;
#else
i4_num_refinement_iterations =
((!ps_ctxt->s_frm_prms.bidir_enabled) && (i4_num_act_ref_l0 > 1)) ? 2 : 1;
#endif
#if ENABLE_EXPLICIT_SEARCH_IN_PQ
if(e_me_quality_presets == ME_PRISTINE_QUALITY)
{
i4_num_refinement_iterations = (u1_pred_dir == 0) ? i4_num_act_ref_l0
: i4_num_act_ref_l1;
}
#endif
for(i4_refine_iter_ctr = 0; i4_refine_iter_ctr < i4_num_refinement_iterations;
i4_refine_iter_ctr++)
{
S32 center_x;
S32 center_y;
S32 center_ref_idx;
S08 *pi1_pred_dir_to_ref_idx =
(u1_pred_dir == 0) ? ps_ctxt->ai1_past_list : ps_ctxt->ai1_future_list;
{
WORD32 i4_i;
for(i4_i = 0; i4_i < TOT_NUM_PARTS; i4_i++)
{
ps_fullpel_refine_ctxt->i2_tot_cost[0][i4_i] = MAX_SIGNED_16BIT_VAL;
ps_fullpel_refine_ctxt->i2_mv_cost[0][i4_i] = MAX_SIGNED_16BIT_VAL;
ps_fullpel_refine_ctxt->i2_stim_injected_cost[0][i4_i] =
MAX_SIGNED_16BIT_VAL;
ps_fullpel_refine_ctxt->i2_mv_x[0][i4_i] = 0;
ps_fullpel_refine_ctxt->i2_mv_y[0][i4_i] = 0;
ps_fullpel_refine_ctxt->i2_ref_idx[0][i4_i] = u1_default_ref_id;
if(ps_refine_prms->i4_num_results_per_part == 2)
{
ps_fullpel_refine_ctxt->i2_tot_cost[1][i4_i] =
MAX_SIGNED_16BIT_VAL;
ps_fullpel_refine_ctxt->i2_mv_cost[1][i4_i] =
MAX_SIGNED_16BIT_VAL;
ps_fullpel_refine_ctxt->i2_stim_injected_cost[1][i4_i] =
MAX_SIGNED_16BIT_VAL;
ps_fullpel_refine_ctxt->i2_mv_x[1][i4_i] = 0;
ps_fullpel_refine_ctxt->i2_mv_y[1][i4_i] = 0;
ps_fullpel_refine_ctxt->i2_ref_idx[1][i4_i] = u1_default_ref_id;
}
}
s_search_prms_blk.ps_fullpel_refine_ctxt = ps_fullpel_refine_ctxt;
s_subpel_prms.ps_subpel_refine_ctxt = ps_fullpel_refine_ctxt;
}
{
search_node_t *ps_coloc_node;
S32 i = 0;
if(i4_num_refinement_iterations > 1)
{
for(i = 0; i < ai4_num_coloc_cands[u1_pred_dir]; i++)
{
ps_coloc_node =
s_search_prms_blk.ps_search_candts[ai4_id_coloc[i]]
.ps_search_node;
if(pi1_pred_dir_to_ref_idx[i4_refine_iter_ctr] ==
ps_coloc_node->i1_ref_idx)
{
break;
}
}
if(i == ai4_num_coloc_cands[u1_pred_dir])
{
i = 0;
}
}
else
{
ps_coloc_node = s_search_prms_blk.ps_search_candts[ai4_id_coloc[0]]
.ps_search_node;
}
hme_set_mvp_node(
ps_search_results,
ps_coloc_node,
u1_pred_dir,
(i4_num_refinement_iterations > 1)
? pi1_pred_dir_to_ref_idx[i4_refine_iter_ctr]
: u1_default_ref_id);
center_x = ps_coloc_node->ps_mv->i2_mvx;
center_y = ps_coloc_node->ps_mv->i2_mvy;
center_ref_idx = ps_coloc_node->i1_ref_idx;
}
/* Full-Pel search */
{
S32 num_unique_nodes;
memset(au4_unique_node_map, 0, sizeof(au4_unique_node_map));
num_unique_nodes = hme_remove_duplicate_fpel_search_candidates(
as_unique_search_nodes,
s_search_prms_blk.ps_search_candts,
au4_unique_node_map,
pi1_pred_dir_to_ref_idx,
i4_num_srch_cands,
s_search_prms_blk.i4_num_init_candts,
i4_refine_iter_ctr,
i4_num_refinement_iterations,
i4_num_act_ref_l0,
center_ref_idx,
center_x,
center_y,
ps_ctxt->s_frm_prms.bidir_enabled,
e_me_quality_presets);
/*************************************************************************/
/* This array stores the ids of the partitions whose */
/* SADs are updated. Since the partitions whose SADs are updated may not */
/* be in contiguous order, we supply another level of indirection. */
/*************************************************************************/
ps_fullpel_refine_ctxt->i4_num_valid_parts = hme_create_valid_part_ids(
s_search_prms_blk.i4_part_mask,
&ps_fullpel_refine_ctxt->ai4_part_id[0]);
if(!i4_refine_iter_ctr && !u1_pred_dir_ctr && u1_is_cu_noisy)
{
S32 i;
/*i4_sigma_array_offset : takes care of pointing to the appropriate 4x4 block's sigmaX and sigmaX-squared value in a CTB out of 256 values*/
S32 i4_sigma_array_offset = (s_search_prms_blk.i4_cu_x_off / 4) +
(s_search_prms_blk.i4_cu_y_off * 4);
for(i = 0; i < ps_fullpel_refine_ctxt->i4_num_valid_parts; i++)
{
S32 i4_part_id = ps_fullpel_refine_ctxt->ai4_part_id[i];
hme_compute_final_sigma_of_pu_from_base_blocks(
ps_ctxt->au4_4x4_src_sigmaX + i4_sigma_array_offset,
ps_ctxt->au4_4x4_src_sigmaXSquared + i4_sigma_array_offset,
au8_final_src_sigmaX,
au8_final_src_sigmaXSquared,
16,
4,
i4_part_id,
16);
}
s_common_frm_prms.pu8_part_src_sigmaX = au8_final_src_sigmaX;
s_common_frm_prms.pu8_part_src_sigmaXSquared =
au8_final_src_sigmaXSquared;
s_search_prms_blk.pu8_part_src_sigmaX = au8_final_src_sigmaX;
s_search_prms_blk.pu8_part_src_sigmaXSquared =
au8_final_src_sigmaXSquared;
}
if(0 == num_unique_nodes)
{
continue;
}
if(num_unique_nodes >= 2)
{
s_search_prms_blk.ps_search_nodes = &as_unique_search_nodes[0];
s_search_prms_blk.i4_num_search_nodes = num_unique_nodes;
if(ps_ctxt->i4_pic_type != IV_P_FRAME)
{
if(ps_ctxt->i4_temporal_layer == 1)
{
hme_fullpel_cand_sifter(
&s_search_prms_blk,
ps_curr_layer,
&ps_ctxt->s_wt_pred,
ALPHA_FOR_NOISE_TERM_IN_ME,
u1_is_cu_noisy,
ps_me_optimised_function_list);
}
else
{
hme_fullpel_cand_sifter(
&s_search_prms_blk,
ps_curr_layer,
&ps_ctxt->s_wt_pred,
ALPHA_FOR_NOISE_TERM_IN_ME,
u1_is_cu_noisy,
ps_me_optimised_function_list);
}
}
else
{
hme_fullpel_cand_sifter(
&s_search_prms_blk,
ps_curr_layer,
&ps_ctxt->s_wt_pred,
ALPHA_FOR_NOISE_TERM_IN_ME_P,
u1_is_cu_noisy,
ps_me_optimised_function_list);
}
}
s_search_prms_blk.ps_search_nodes = &as_unique_search_nodes[0];
hme_fullpel_refine(
ps_refine_prms,
&s_search_prms_blk,
ps_curr_layer,
&ps_ctxt->s_wt_pred,
au4_unique_node_map,
num_unique_nodes,
blk_8x8_mask,
center_x,
center_y,
center_ref_idx,
e_me_quality_presets,
ps_me_optimised_function_list);
}
/* Sub-Pel search */
{
hme_reset_wkg_mem(&ps_ctxt->s_buf_mgr);
s_subpel_prms.pu1_wkg_mem = (U08 *)hme_get_wkg_mem(
&ps_ctxt->s_buf_mgr,
INTERP_INTERMED_BUF_SIZE + INTERP_OUT_BUF_SIZE);
/* MV limit is different based on ref. PIC */
for(ref_ctr = 0; ref_ctr < num_act_ref_pics; ref_ctr++)
{
SCALE_RANGE_PRMS(
as_range_prms_hpel[ref_ctr], as_range_prms_rec[ref_ctr], 1);
SCALE_RANGE_PRMS(
as_range_prms_qpel[ref_ctr], as_range_prms_rec[ref_ctr], 2);
}
s_subpel_prms.i4_ctb_x_off = i4_ctb_x << 6;
s_subpel_prms.i4_ctb_y_off = i4_ctb_y << 6;
hme_subpel_refine_cu_hs(
&s_subpel_prms,
ps_curr_layer,
ps_search_results,
u1_pred_dir,
&ps_ctxt->s_wt_pred,
blk_8x8_mask,
ps_ctxt->ps_func_selector,
ps_cmn_utils_optimised_function_list,
ps_me_optimised_function_list);
}
}
}
/* Populate the new PU struct with the results post subpel refinement*/
{
inter_cu_results_t *ps_cu_results;
WORD32 best_inter_cost, intra_cost, posx, posy;
UWORD8 intra_8x8_enabled = 0;
/* cost of 16x16 cu parent */
WORD32 parent_cost = MAX_32BIT_VAL;
/* cost of 8x8 cu children */
/*********************************************************************/
/* Assuming parent is not split, then we signal 1 bit for this parent*/
/* CU. If split, then 1 bit for parent CU + 4 bits for each child CU */
/* So, 4*lambda is extra for children cost. */
/*********************************************************************/
WORD32 child_cost = 0;
ps_cu_results = ps_search_results->ps_cu_results;
/* Initialize the pu_results pointers to the first struct in the stack array */
ps_pu_results = as_inter_pu_results;
hme_reset_wkg_mem(&ps_ctxt->s_buf_mgr);
hme_populate_pus(
ps_thrd_ctxt,
ps_ctxt,
&s_subpel_prms,
ps_search_results,
ps_cu_results,
ps_pu_results,
&(as_pu_results[0][0][0]),
&s_common_frm_prms,
&ps_ctxt->s_wt_pred,
ps_curr_layer,
au1_pred_dir_searched,
i4_num_pred_dir);
ps_cu_results->i4_inp_offset =
(ps_cu_results->u1_x_off) + (ps_cu_results->u1_y_off * 64);
hme_decide_part_types(
ps_cu_results,
ps_pu_results,
&s_common_frm_prms,
ps_ctxt,
ps_cmn_utils_optimised_function_list,
ps_me_optimised_function_list
);
/* UPDATE the MIN and MAX MVs for Dynamical Search Range for each ref. pic. */
/* Only for P pic. For P, both are 0, I&B has them mut. exclusive */
if(ps_ctxt->s_frm_prms.is_i_pic == ps_ctxt->s_frm_prms.bidir_enabled)
{
WORD32 res_ctr;
for(res_ctr = 0; res_ctr < ps_cu_results->u1_num_best_results; res_ctr++)
{
WORD32 num_part = 2, part_ctr;
part_type_results_t *ps_best_results =
&ps_cu_results->ps_best_results[res_ctr];
if(PRT_2Nx2N == ps_best_results->u1_part_type)
num_part = 1;
for(part_ctr = 0; part_ctr < num_part; part_ctr++)
{
pu_result_t *ps_pu_results =
&ps_best_results->as_pu_results[part_ctr];
ASSERT(PRED_L0 == ps_pu_results->pu.b2_pred_mode);
hme_update_dynamic_search_params(
&ps_ctxt->as_l0_dyn_range_prms[i4_idx_dvsr_p]
.as_dyn_range_prms[ps_pu_results->pu.mv.i1_l0_ref_idx],
ps_pu_results->pu.mv.s_l0_mv.i2_mvy);
/* Sanity Check */
ASSERT(
ps_pu_results->pu.mv.i1_l0_ref_idx <
ps_ctxt->s_frm_prms.u1_num_active_ref_l0);
/* No L1 for P Pic. */
ASSERT(PRED_L1 != ps_pu_results->pu.b2_pred_mode);
/* No BI for P Pic. */
ASSERT(PRED_BI != ps_pu_results->pu.b2_pred_mode);
}
}
}
/*****************************************************************/
/* INSERT INTRA RESULTS AT 16x16 LEVEL. */
/*****************************************************************/
#if DISABLE_INTRA_IN_BPICS
if(1 != ((ME_XTREME_SPEED_25 == e_me_quality_presets) &&
(ps_ctxt->s_frm_prms.i4_temporal_layer_id > TEMPORAL_LAYER_DISABLE)))
#endif
{
if(!(DISABLE_INTRA_WHEN_NOISY && s_common_frm_prms.u1_is_cu_noisy))
{
hme_insert_intra_nodes_post_bipred(
ps_cu_results, ps_cur_ipe_ctb, ps_ctxt->frm_qstep);
}
}
#if DISABLE_INTRA_IN_BPICS
if((ME_XTREME_SPEED_25 == e_me_quality_presets) &&
(ps_ctxt->s_frm_prms.i4_temporal_layer_id > TEMPORAL_LAYER_DISABLE))
{
intra_8x8_enabled = 0;
}
else
#endif
{
/*TRAQO intra flag updation*/
if(1 == ps_cu_results->ps_best_results->as_pu_results[0].pu.b1_intra_flag)
{
best_inter_cost =
ps_cu_results->ps_best_results->as_pu_results[1].i4_tot_cost;
intra_cost =
ps_cu_results->ps_best_results->as_pu_results[0].i4_tot_cost;
/*@16x16 level*/
posx = (ps_cu_results->ps_best_results->as_pu_results[1].pu.b4_pos_x
<< 2) >>
4;
posy = (ps_cu_results->ps_best_results->as_pu_results[1].pu.b4_pos_y
<< 2) >>
4;
}
else
{
best_inter_cost =
ps_cu_results->ps_best_results->as_pu_results[0].i4_tot_cost;
posx = (ps_cu_results->ps_best_results->as_pu_results[0].pu.b4_pos_x
<< 2) >>
3;
posy = (ps_cu_results->ps_best_results->as_pu_results[0].pu.b4_pos_y
<< 2) >>
3;
}
/* Disable intra16/32/64 flags based on split flags recommended by IPE */
if(ps_cur_ipe_ctb->u1_split_flag)
{
/* Id of the 32x32 block, 16x16 block in a CTB */
WORD32 i4_32x32_id =
(ps_cu_results->u1_y_off >> 5) * 2 + (ps_cu_results->u1_x_off >> 5);
WORD32 i4_16x16_id = ((ps_cu_results->u1_y_off >> 4) & 0x1) * 2 +
((ps_cu_results->u1_x_off >> 4) & 0x1);
if(ps_cur_ipe_ctb->as_intra32_analyse[i4_32x32_id].b1_split_flag)
{
if(ps_cur_ipe_ctb->as_intra32_analyse[i4_32x32_id]
.as_intra16_analyse[i4_16x16_id]
.b1_split_flag)
{
intra_8x8_enabled =
ps_cur_ipe_ctb->as_intra32_analyse[i4_32x32_id]
.as_intra16_analyse[i4_16x16_id]
.as_intra8_analyse[0]
.b1_valid_cu;
intra_8x8_enabled &=
ps_cur_ipe_ctb->as_intra32_analyse[i4_32x32_id]
.as_intra16_analyse[i4_16x16_id]
.as_intra8_analyse[1]
.b1_valid_cu;
intra_8x8_enabled &=
ps_cur_ipe_ctb->as_intra32_analyse[i4_32x32_id]
.as_intra16_analyse[i4_16x16_id]
.as_intra8_analyse[2]
.b1_valid_cu;
intra_8x8_enabled &=
ps_cur_ipe_ctb->as_intra32_analyse[i4_32x32_id]
.as_intra16_analyse[i4_16x16_id]
.as_intra8_analyse[3]
.b1_valid_cu;
}
}
}
}
if(blk_8x8_mask == 0xf)
{
parent_cost =
ps_search_results->ps_cu_results->ps_best_results[0].i4_tot_cost;
ps_search_results->u1_split_flag = 0;
}
else
{
ps_search_results->u1_split_flag = 1;
}
ps_cu_results = &ps_ctxt->as_cu8x8_results[blk_id_in_full_ctb << 2];
if(s_common_frm_prms.u1_is_cu_noisy)
{
intra_8x8_enabled = 0;
}
/* Evalaute 8x8 if NxN part id is enabled */
if((ps_search_results->i4_part_mask & ENABLE_NxN) || intra_8x8_enabled)
{
/* Populates the PU's for the 4 8x8's in one call */
hme_populate_pus_8x8_cu(
ps_thrd_ctxt,
ps_ctxt,
&s_subpel_prms,
ps_search_results,
ps_cu_results,
ps_pu_results,
&(as_pu_results[0][0][0]),
&s_common_frm_prms,
au1_pred_dir_searched,
i4_num_pred_dir,
blk_8x8_mask);
/* Re-initialize the pu_results pointers to the first struct in the stack array */
ps_pu_results = as_inter_pu_results;
for(i = 0; i < 4; i++)
{
if((blk_8x8_mask & (1 << i)))
{
if(ps_cu_results->i4_part_mask)
{
hme_decide_part_types(
ps_cu_results,
ps_pu_results,
&s_common_frm_prms,
ps_ctxt,
ps_cmn_utils_optimised_function_list,
ps_me_optimised_function_list
);
}
/*****************************************************************/
/* INSERT INTRA RESULTS AT 8x8 LEVEL. */
/*****************************************************************/
#if DISABLE_INTRA_IN_BPICS
if(1 != ((ME_XTREME_SPEED_25 == e_me_quality_presets) &&
(ps_ctxt->s_frm_prms.i4_temporal_layer_id >
TEMPORAL_LAYER_DISABLE)))
#endif
{
if(!(DISABLE_INTRA_WHEN_NOISY &&
s_common_frm_prms.u1_is_cu_noisy))
{
hme_insert_intra_nodes_post_bipred(
ps_cu_results, ps_cur_ipe_ctb, ps_ctxt->frm_qstep);
}
}
child_cost += ps_cu_results->ps_best_results[0].i4_tot_cost;
}
ps_cu_results++;
ps_pu_results++;
}
/* Compare 16x16 vs 8x8 cost */
if(child_cost < parent_cost)
{
ps_search_results->best_cu_cost = child_cost;
ps_search_results->u1_split_flag = 1;
}
}
}
hme_update_mv_bank_encode(
ps_search_results,
ps_curr_layer->ps_layer_mvbank,
blk_x,
blk_y,
&s_mv_update_prms,
au1_pred_dir_searched,
i4_num_act_ref_l0);
/*********************************************************************/
/* Map the best results to an MV Grid. This is a 18x18 grid that is */
/* useful for doing things like predictor for cost calculation or */
/* also for merge calculations if need be. */
/*********************************************************************/
hme_map_mvs_to_grid(
&aps_mv_grid[0], ps_search_results, au1_pred_dir_searched, i4_num_pred_dir);
}
/* Set the CU tree nodes appropriately */
if(e_me_quality_presets != ME_PRISTINE_QUALITY)
{
WORD32 i, j;
for(i = 0; i < 16; i++)
{
cur_ctb_cu_tree_t *ps_tree_node =
ps_ctxt->ps_cu_tree_curr_row + (i4_ctb_x * MAX_NUM_NODES_CU_TREE);
search_results_t *ps_results = &ps_ctxt->as_search_results_16x16[i];
switch(i >> 2)
{
case 0:
{
ps_tree_node = ps_tree_node->ps_child_node_tl;
break;
}
case 1:
{
ps_tree_node = ps_tree_node->ps_child_node_tr;
break;
}
case 2:
{
ps_tree_node = ps_tree_node->ps_child_node_bl;
break;
}
case 3:
{
ps_tree_node = ps_tree_node->ps_child_node_br;
break;
}
}
switch(i % 4)
{
case 0:
{
ps_tree_node = ps_tree_node->ps_child_node_tl;
break;
}
case 1:
{
ps_tree_node = ps_tree_node->ps_child_node_tr;
break;
}
case 2:
{
ps_tree_node = ps_tree_node->ps_child_node_bl;
break;
}
case 3:
{
ps_tree_node = ps_tree_node->ps_child_node_br;
break;
}
}
if(ai4_blk_8x8_mask[i] == 15)
{
if(!ps_results->u1_split_flag)
{
ps_tree_node->is_node_valid = 1;
NULLIFY_THE_CHILDREN_NODES(ps_tree_node);
}
else
{
ps_tree_node->is_node_valid = 0;
ENABLE_THE_CHILDREN_NODES(ps_tree_node);
}
}
else
{
cur_ctb_cu_tree_t *ps_tree_child;
ps_tree_node->is_node_valid = 0;
for(j = 0; j < 4; j++)
{
switch(j)
{
case 0:
{
ps_tree_child = ps_tree_node->ps_child_node_tl;
break;
}
case 1:
{
ps_tree_child = ps_tree_node->ps_child_node_tr;
break;
}
case 2:
{
ps_tree_child = ps_tree_node->ps_child_node_bl;
break;
}
case 3:
{
ps_tree_child = ps_tree_node->ps_child_node_br;
break;
}
}
ps_tree_child->is_node_valid = !!(ai4_blk_8x8_mask[i] & (1 << j));
}
}
}
}
if(ME_PRISTINE_QUALITY == e_me_quality_presets)
{
cur_ctb_cu_tree_t *ps_tree = ps_ctb_cluster_info->ps_cu_tree_root;
hme_analyse_mv_clustering(
ps_ctxt->as_search_results_16x16,
ps_ctxt->as_cu16x16_results,
ps_ctxt->as_cu8x8_results,
ps_ctxt->ps_ctb_cluster_info,
ps_ctxt->ai1_future_list,
ps_ctxt->ai1_past_list,
ps_ctxt->s_frm_prms.bidir_enabled,
e_me_quality_presets);
#if DISABLE_BLK_MERGE_WHEN_NOISY
ps_tree->ps_child_node_tl->is_node_valid = !au1_is_32x32Blk_noisy[0];
ps_tree->ps_child_node_tr->is_node_valid = !au1_is_32x32Blk_noisy[1];
ps_tree->ps_child_node_bl->is_node_valid = !au1_is_32x32Blk_noisy[2];
ps_tree->ps_child_node_br->is_node_valid = !au1_is_32x32Blk_noisy[3];
ps_tree->ps_child_node_tl->u1_inter_eval_enable = !au1_is_32x32Blk_noisy[0];
ps_tree->ps_child_node_tr->u1_inter_eval_enable = !au1_is_32x32Blk_noisy[1];
ps_tree->ps_child_node_bl->u1_inter_eval_enable = !au1_is_32x32Blk_noisy[2];
ps_tree->ps_child_node_br->u1_inter_eval_enable = !au1_is_32x32Blk_noisy[3];
ps_tree->is_node_valid = !au1_is_64x64Blk_noisy[0];
ps_tree->u1_inter_eval_enable = !au1_is_64x64Blk_noisy[0];
#endif
en_merge_32x32 = (ps_tree->ps_child_node_tl->is_node_valid << 0) |
(ps_tree->ps_child_node_tr->is_node_valid << 1) |
(ps_tree->ps_child_node_bl->is_node_valid << 2) |
(ps_tree->ps_child_node_br->is_node_valid << 3);
en_merge_execution = (ps_tree->ps_child_node_tl->u1_inter_eval_enable << 0) |
(ps_tree->ps_child_node_tr->u1_inter_eval_enable << 1) |
(ps_tree->ps_child_node_bl->u1_inter_eval_enable << 2) |
(ps_tree->ps_child_node_br->u1_inter_eval_enable << 3) |
(ps_tree->u1_inter_eval_enable << 4);
}
else
{
en_merge_execution = 0x1f;
#if DISABLE_BLK_MERGE_WHEN_NOISY
en_merge_32x32 = ((!au1_is_32x32Blk_noisy[0] << 0) & (en_merge_32x32 & 1)) |
((!au1_is_32x32Blk_noisy[1] << 1) & (en_merge_32x32 & 2)) |
((!au1_is_32x32Blk_noisy[2] << 2) & (en_merge_32x32 & 4)) |
((!au1_is_32x32Blk_noisy[3] << 3) & (en_merge_32x32 & 8));
#endif
}
/* Re-initialize the pu_results pointers to the first struct in the stack array */
ps_pu_results = as_inter_pu_results;
{
WORD32 ref_ctr;
s_ctb_prms.i4_ctb_x = i4_ctb_x << 6;
s_ctb_prms.i4_ctb_y = i4_ctb_y << 6;
/* MV limit is different based on ref. PIC */
for(ref_ctr = 0; ref_ctr < num_act_ref_pics; ref_ctr++)
{
SCALE_RANGE_PRMS(as_range_prms_hpel[ref_ctr], as_range_prms_rec[ref_ctr], 1);
SCALE_RANGE_PRMS(as_range_prms_qpel[ref_ctr], as_range_prms_rec[ref_ctr], 2);
}
e_merge_result = CU_SPLIT;
merge_count_32x32 = 0;
if((en_merge_32x32 & 1) && (en_merge_execution & 1))
{
range_prms_t *ps_pic_limit;
if(s_merge_prms_32x32_tl.i4_use_rec == 1)
{
ps_pic_limit = &s_pic_limit_rec;
}
else
{
ps_pic_limit = &s_pic_limit_inp;
}
/* MV limit is different based on ref. PIC */
for(ref_ctr = 0; ref_ctr < num_act_ref_pics; ref_ctr++)
{
hme_derive_search_range(
s_merge_prms_32x32_tl.aps_mv_range[ref_ctr],
ps_pic_limit,
&as_mv_limit[ref_ctr],
i4_ctb_x << 6,
i4_ctb_y << 6,
32,
32);
SCALE_RANGE_PRMS_POINTERS(
s_merge_prms_32x32_tl.aps_mv_range[ref_ctr],
s_merge_prms_32x32_tl.aps_mv_range[ref_ctr],
2);
}
s_merge_prms_32x32_tl.i4_ctb_x_off = i4_ctb_x << 6;
s_merge_prms_32x32_tl.i4_ctb_y_off = i4_ctb_y << 6;
s_subpel_prms.u1_is_cu_noisy = au1_is_32x32Blk_noisy[0];
e_merge_result = hme_try_merge_high_speed(
ps_thrd_ctxt,
ps_ctxt,
ps_cur_ipe_ctb,
&s_subpel_prms,
&s_merge_prms_32x32_tl,
ps_pu_results,
&as_pu_results[0][0][0]);
if(e_merge_result == CU_MERGED)
{
inter_cu_results_t *ps_cu_results =
s_merge_prms_32x32_tl.ps_results_merge->ps_cu_results;
if(!((ps_cu_results->u1_num_best_results == 1) &&
(ps_cu_results->ps_best_results->as_pu_results->pu.b1_intra_flag)))
{
hme_map_mvs_to_grid(
&aps_mv_grid[0],
s_merge_prms_32x32_tl.ps_results_merge,
s_merge_prms_32x32_tl.au1_pred_dir_searched,
s_merge_prms_32x32_tl.i4_num_pred_dir_actual);
}
if(ME_PRISTINE_QUALITY != e_me_quality_presets)
{
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.ps_child_node_tl->is_node_valid = 1;
NULLIFY_THE_CHILDREN_NODES(
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.ps_child_node_tl);
}
merge_count_32x32++;
e_merge_result = CU_SPLIT;
}
else if(ME_PRISTINE_QUALITY == e_me_quality_presets)
{
#if ENABLE_CU_TREE_CULLING
cur_ctb_cu_tree_t *ps_tree =
ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_tl;
ps_ctb_cluster_info->ps_cu_tree_root->is_node_valid = 0;
en_merge_execution = (en_merge_execution & (~(1 << 4)));
ENABLE_THE_CHILDREN_NODES(ps_tree);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tr);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_bl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_br);
#endif
}
}
else if((en_merge_32x32 & 1) && (!(en_merge_execution & 1)))
{
#if ENABLE_CU_TREE_CULLING
cur_ctb_cu_tree_t *ps_tree =
ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_tl;
ENABLE_THE_CHILDREN_NODES(ps_tree);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tr);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_bl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_br);
#endif
if(au1_is_32x32Blk_noisy[0] && DISABLE_INTRA_WHEN_NOISY)
{
ps_tree->is_node_valid = 0;
ps_ctb_cluster_info->ps_cu_tree_root->is_node_valid = 0;
en_merge_execution = (en_merge_execution & (~(1 << 4)));
}
}
if((en_merge_32x32 & 2) && (en_merge_execution & 2))
{
range_prms_t *ps_pic_limit;
if(s_merge_prms_32x32_tr.i4_use_rec == 1)
{
ps_pic_limit = &s_pic_limit_rec;
}
else
{
ps_pic_limit = &s_pic_limit_inp;
}
/* MV limit is different based on ref. PIC */
for(ref_ctr = 0; ref_ctr < num_act_ref_pics; ref_ctr++)
{
hme_derive_search_range(
s_merge_prms_32x32_tr.aps_mv_range[ref_ctr],
ps_pic_limit,
&as_mv_limit[ref_ctr],
(i4_ctb_x << 6) + 32,
i4_ctb_y << 6,
32,
32);
SCALE_RANGE_PRMS_POINTERS(
s_merge_prms_32x32_tr.aps_mv_range[ref_ctr],
s_merge_prms_32x32_tr.aps_mv_range[ref_ctr],
2);
}
s_merge_prms_32x32_tr.i4_ctb_x_off = i4_ctb_x << 6;
s_merge_prms_32x32_tr.i4_ctb_y_off = i4_ctb_y << 6;
s_subpel_prms.u1_is_cu_noisy = au1_is_32x32Blk_noisy[1];
e_merge_result = hme_try_merge_high_speed(
ps_thrd_ctxt,
ps_ctxt,
ps_cur_ipe_ctb,
&s_subpel_prms,
&s_merge_prms_32x32_tr,
ps_pu_results,
&as_pu_results[0][0][0]);
if(e_merge_result == CU_MERGED)
{
inter_cu_results_t *ps_cu_results =
s_merge_prms_32x32_tr.ps_results_merge->ps_cu_results;
if(!((ps_cu_results->u1_num_best_results == 1) &&
(ps_cu_results->ps_best_results->as_pu_results->pu.b1_intra_flag)))
{
hme_map_mvs_to_grid(
&aps_mv_grid[0],
s_merge_prms_32x32_tr.ps_results_merge,
s_merge_prms_32x32_tr.au1_pred_dir_searched,
s_merge_prms_32x32_tr.i4_num_pred_dir_actual);
}
if(ME_PRISTINE_QUALITY != e_me_quality_presets)
{
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.ps_child_node_tr->is_node_valid = 1;
NULLIFY_THE_CHILDREN_NODES(
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.ps_child_node_tr);
}
merge_count_32x32++;
e_merge_result = CU_SPLIT;
}
else if(ME_PRISTINE_QUALITY == e_me_quality_presets)
{
#if ENABLE_CU_TREE_CULLING
cur_ctb_cu_tree_t *ps_tree =
ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_tr;
ps_ctb_cluster_info->ps_cu_tree_root->is_node_valid = 0;
en_merge_execution = (en_merge_execution & (~(1 << 4)));
ENABLE_THE_CHILDREN_NODES(ps_tree);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tr);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_bl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_br);
#endif
}
}
else if((en_merge_32x32 & 2) && (!(en_merge_execution & 2)))
{
#if ENABLE_CU_TREE_CULLING
cur_ctb_cu_tree_t *ps_tree =
ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_tr;
ENABLE_THE_CHILDREN_NODES(ps_tree);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tr);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_bl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_br);
#endif
if(au1_is_32x32Blk_noisy[1] && DISABLE_INTRA_WHEN_NOISY)
{
ps_tree->is_node_valid = 0;
ps_ctb_cluster_info->ps_cu_tree_root->is_node_valid = 0;
en_merge_execution = (en_merge_execution & (~(1 << 4)));
}
}
if((en_merge_32x32 & 4) && (en_merge_execution & 4))
{
range_prms_t *ps_pic_limit;
if(s_merge_prms_32x32_bl.i4_use_rec == 1)
{
ps_pic_limit = &s_pic_limit_rec;
}
else
{
ps_pic_limit = &s_pic_limit_inp;
}
/* MV limit is different based on ref. PIC */
for(ref_ctr = 0; ref_ctr < num_act_ref_pics; ref_ctr++)
{
hme_derive_search_range(
s_merge_prms_32x32_bl.aps_mv_range[ref_ctr],
ps_pic_limit,
&as_mv_limit[ref_ctr],
i4_ctb_x << 6,
(i4_ctb_y << 6) + 32,
32,
32);
SCALE_RANGE_PRMS_POINTERS(
s_merge_prms_32x32_bl.aps_mv_range[ref_ctr],
s_merge_prms_32x32_bl.aps_mv_range[ref_ctr],
2);
}
s_merge_prms_32x32_bl.i4_ctb_x_off = i4_ctb_x << 6;
s_merge_prms_32x32_bl.i4_ctb_y_off = i4_ctb_y << 6;
s_subpel_prms.u1_is_cu_noisy = au1_is_32x32Blk_noisy[2];
e_merge_result = hme_try_merge_high_speed(
ps_thrd_ctxt,
ps_ctxt,
ps_cur_ipe_ctb,
&s_subpel_prms,
&s_merge_prms_32x32_bl,
ps_pu_results,
&as_pu_results[0][0][0]);
if(e_merge_result == CU_MERGED)
{
inter_cu_results_t *ps_cu_results =
s_merge_prms_32x32_bl.ps_results_merge->ps_cu_results;
if(!((ps_cu_results->u1_num_best_results == 1) &&
(ps_cu_results->ps_best_results->as_pu_results->pu.b1_intra_flag)))
{
hme_map_mvs_to_grid(
&aps_mv_grid[0],
s_merge_prms_32x32_bl.ps_results_merge,
s_merge_prms_32x32_bl.au1_pred_dir_searched,
s_merge_prms_32x32_bl.i4_num_pred_dir_actual);
}
if(ME_PRISTINE_QUALITY != e_me_quality_presets)
{
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.ps_child_node_bl->is_node_valid = 1;
NULLIFY_THE_CHILDREN_NODES(
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.ps_child_node_bl);
}
merge_count_32x32++;
e_merge_result = CU_SPLIT;
}
else if(ME_PRISTINE_QUALITY == e_me_quality_presets)
{
#if ENABLE_CU_TREE_CULLING
cur_ctb_cu_tree_t *ps_tree =
ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_bl;
ps_ctb_cluster_info->ps_cu_tree_root->is_node_valid = 0;
en_merge_execution = (en_merge_execution & (~(1 << 4)));
ENABLE_THE_CHILDREN_NODES(ps_tree);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tr);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_bl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_br);
#endif
}
}
else if((en_merge_32x32 & 4) && (!(en_merge_execution & 4)))
{
#if ENABLE_CU_TREE_CULLING
cur_ctb_cu_tree_t *ps_tree =
ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_bl;
ENABLE_THE_CHILDREN_NODES(ps_tree);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tr);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_bl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_br);
#endif
if(au1_is_32x32Blk_noisy[2] && DISABLE_INTRA_WHEN_NOISY)
{
ps_tree->is_node_valid = 0;
ps_ctb_cluster_info->ps_cu_tree_root->is_node_valid = 0;
en_merge_execution = (en_merge_execution & (~(1 << 4)));
}
}
if((en_merge_32x32 & 8) && (en_merge_execution & 8))
{
range_prms_t *ps_pic_limit;
if(s_merge_prms_32x32_br.i4_use_rec == 1)
{
ps_pic_limit = &s_pic_limit_rec;
}
else
{
ps_pic_limit = &s_pic_limit_inp;
}
/* MV limit is different based on ref. PIC */
for(ref_ctr = 0; ref_ctr < num_act_ref_pics; ref_ctr++)
{
hme_derive_search_range(
s_merge_prms_32x32_br.aps_mv_range[ref_ctr],
ps_pic_limit,
&as_mv_limit[ref_ctr],
(i4_ctb_x << 6) + 32,
(i4_ctb_y << 6) + 32,
32,
32);
SCALE_RANGE_PRMS_POINTERS(
s_merge_prms_32x32_br.aps_mv_range[ref_ctr],
s_merge_prms_32x32_br.aps_mv_range[ref_ctr],
2);
}
s_merge_prms_32x32_br.i4_ctb_x_off = i4_ctb_x << 6;
s_merge_prms_32x32_br.i4_ctb_y_off = i4_ctb_y << 6;
s_subpel_prms.u1_is_cu_noisy = au1_is_32x32Blk_noisy[3];
e_merge_result = hme_try_merge_high_speed(
ps_thrd_ctxt,
ps_ctxt,
ps_cur_ipe_ctb,
&s_subpel_prms,
&s_merge_prms_32x32_br,
ps_pu_results,
&as_pu_results[0][0][0]);
if(e_merge_result == CU_MERGED)
{
/*inter_cu_results_t *ps_cu_results = s_merge_prms_32x32_br.ps_results_merge->ps_cu_results;
if(!((ps_cu_results->u1_num_best_results == 1) &&
(ps_cu_results->ps_best_results->as_pu_results->pu.b1_intra_flag)))
{
hme_map_mvs_to_grid
(
&aps_mv_grid[0],
s_merge_prms_32x32_br.ps_results_merge,
s_merge_prms_32x32_br.au1_pred_dir_searched,
s_merge_prms_32x32_br.i4_num_pred_dir_actual
);
}*/
if(ME_PRISTINE_QUALITY != e_me_quality_presets)
{
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.ps_child_node_br->is_node_valid = 1;
NULLIFY_THE_CHILDREN_NODES(
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.ps_child_node_br);
}
merge_count_32x32++;
e_merge_result = CU_SPLIT;
}
else if(ME_PRISTINE_QUALITY == e_me_quality_presets)
{
#if ENABLE_CU_TREE_CULLING
cur_ctb_cu_tree_t *ps_tree =
ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_br;
ps_ctb_cluster_info->ps_cu_tree_root->is_node_valid = 0;
en_merge_execution = (en_merge_execution & (~(1 << 4)));
ENABLE_THE_CHILDREN_NODES(ps_tree);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tr);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_bl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_br);
#endif
}
}
else if((en_merge_32x32 & 8) && (!(en_merge_execution & 8)))
{
#if ENABLE_CU_TREE_CULLING
cur_ctb_cu_tree_t *ps_tree =
ps_ctb_cluster_info->ps_cu_tree_root->ps_child_node_br;
ENABLE_THE_CHILDREN_NODES(ps_tree);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_tr);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_bl);
ENABLE_THE_CHILDREN_NODES(ps_tree->ps_child_node_br);
#endif
if(au1_is_32x32Blk_noisy[3] && DISABLE_INTRA_WHEN_NOISY)
{
ps_tree->is_node_valid = 0;
ps_ctb_cluster_info->ps_cu_tree_root->is_node_valid = 0;
en_merge_execution = (en_merge_execution & (~(1 << 4)));
}
}
/* Try merging all 32x32 to 64x64 candts */
if(((en_merge_32x32 & 0xf) == 0xf) &&
(((merge_count_32x32 == 4) && (e_me_quality_presets != ME_PRISTINE_QUALITY)) ||
((en_merge_execution & 16) && (e_me_quality_presets == ME_PRISTINE_QUALITY))))
if((((e_me_quality_presets == ME_XTREME_SPEED_25) &&
!DISABLE_64X64_BLOCK_MERGE_IN_ME_IN_XS25) ||
(e_me_quality_presets != ME_XTREME_SPEED_25)))
{
range_prms_t *ps_pic_limit;
if(s_merge_prms_64x64.i4_use_rec == 1)
{
ps_pic_limit = &s_pic_limit_rec;
}
else
{
ps_pic_limit = &s_pic_limit_inp;
}
/* MV limit is different based on ref. PIC */
for(ref_ctr = 0; ref_ctr < num_act_ref_pics; ref_ctr++)
{
hme_derive_search_range(
s_merge_prms_64x64.aps_mv_range[ref_ctr],
ps_pic_limit,
&as_mv_limit[ref_ctr],
i4_ctb_x << 6,
i4_ctb_y << 6,
64,
64);
SCALE_RANGE_PRMS_POINTERS(
s_merge_prms_64x64.aps_mv_range[ref_ctr],
s_merge_prms_64x64.aps_mv_range[ref_ctr],
2);
}
s_merge_prms_64x64.i4_ctb_x_off = i4_ctb_x << 6;
s_merge_prms_64x64.i4_ctb_y_off = i4_ctb_y << 6;
s_subpel_prms.u1_is_cu_noisy = au1_is_64x64Blk_noisy[0];
e_merge_result = hme_try_merge_high_speed(
ps_thrd_ctxt,
ps_ctxt,
ps_cur_ipe_ctb,
&s_subpel_prms,
&s_merge_prms_64x64,
ps_pu_results,
&as_pu_results[0][0][0]);
if((e_merge_result == CU_MERGED) &&
(ME_PRISTINE_QUALITY != e_me_quality_presets))
{
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.is_node_valid = 1;
NULLIFY_THE_CHILDREN_NODES(
ps_ctxt->ps_cu_tree_curr_row + (i4_ctb_x * MAX_NUM_NODES_CU_TREE));
}
else if(
(e_merge_result == CU_SPLIT) &&
(ME_PRISTINE_QUALITY == e_me_quality_presets))
{
ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]
.is_node_valid = 0;
}
}
/*****************************************************************/
/* UPDATION OF RESULT TO EXTERNAL STRUCTURES */
/*****************************************************************/
pf_ext_update_fxn((void *)ps_thrd_ctxt, (void *)ps_ctxt, i4_ctb_x, i4_ctb_y);
{
#ifdef _DEBUG
S32 wd = ((i4_pic_wd - s_common_frm_prms.i4_ctb_x_off) >= 64)
? 64
: i4_pic_wd - s_common_frm_prms.i4_ctb_x_off;
S32 ht = ((i4_pic_ht - s_common_frm_prms.i4_ctb_y_off) >= 64)
? 64
: i4_pic_ht - s_common_frm_prms.i4_ctb_y_off;
ASSERT(
(wd * ht) ==
ihevce_compute_area_of_valid_cus_in_ctb(
&ps_ctxt->ps_cu_tree_curr_row[(i4_ctb_x * MAX_NUM_NODES_CU_TREE)]));
#endif
}
}
/* set the dependency for the corresponding row in enc loop */
ihevce_dmgr_set_row_row_sync(
pv_dep_mngr_encloop_dep_me,
(i4_ctb_x + 1),
i4_ctb_y,
tile_col_idx /* Col Tile No. */);
left_ctb_in_diff_tile = 0;
}
}
}
/**
********************************************************************************
* @fn void hme_refine_no_encode(coarse_me_ctxt_t *ps_ctxt,
* refine_layer_prms_t *ps_refine_prms)
*
* @brief Top level entry point for refinement ME
*
* @param[in,out] ps_ctxt: ME Handle
*
* @param[in] ps_refine_prms : refinement layer prms
*
* @return None
********************************************************************************
*/
void hme_refine_no_encode(
coarse_me_ctxt_t *ps_ctxt,
refine_prms_t *ps_refine_prms,
multi_thrd_ctxt_t *ps_multi_thrd_ctxt,
S32 lyr_job_type,
WORD32 i4_ping_pong,
void **ppv_dep_mngr_hme_sync)
{
BLK_SIZE_T e_search_blk_size, e_result_blk_size;
ME_QUALITY_PRESETS_T e_me_quality_presets =
ps_ctxt->s_init_prms.s_me_coding_tools.e_me_quality_presets;
/*************************************************************************/
/* Complexity of search: Low to High */
/*************************************************************************/
SEARCH_COMPLEXITY_T e_search_complexity;
/*************************************************************************/
/* Config parameter structures for varius ME submodules */
/*************************************************************************/
hme_search_prms_t s_search_prms_blk;
mvbank_update_prms_t s_mv_update_prms;
/*************************************************************************/
/* All types of search candidates for predictor based search. */
/*************************************************************************/
S32 num_init_candts = 0;
search_candt_t *ps_search_candts, as_search_candts[MAX_INIT_CANDTS];
search_node_t as_top_neighbours[4], as_left_neighbours[3];
search_node_t *ps_candt_zeromv, *ps_candt_tl, *ps_candt_tr;
search_node_t *ps_candt_l, *ps_candt_t;
search_node_t *ps_candt_prj_br[2], *ps_candt_prj_b[2], *ps_candt_prj_r[2];
search_node_t *ps_candt_prj_bl[2];
search_node_t *ps_candt_prj_tr[2], *ps_candt_prj_t[2], *ps_candt_prj_tl[2];
search_node_t *ps_candt_prj_coloc[2];
pf_get_wt_inp fp_get_wt_inp;
search_node_t as_unique_search_nodes[MAX_INIT_CANDTS * 9];
U32 au4_unique_node_map[MAP_X_MAX * 2];
/*EIID */
WORD32 i4_num_inter_wins = 0; //debug code to find stat of
WORD32 i4_num_comparisions = 0; //debug code
WORD32 i4_threshold_multiplier;
WORD32 i4_threshold_divider;
WORD32 i4_temporal_layer =
ps_multi_thrd_ctxt->aps_curr_inp_pre_enc[i4_ping_pong]->s_lap_out.i4_temporal_lyr_id;
/*************************************************************************/
/* points ot the search results for the blk level search (8x8/16x16) */
/*************************************************************************/
search_results_t *ps_search_results;
/*************************************************************************/
/* Coordinates */
/*************************************************************************/
S32 blk_x, i4_ctb_x, blk_id_in_ctb;
//S32 i4_ctb_y;
S32 pos_x, pos_y;
S32 blk_id_in_full_ctb;
S32 i4_num_srch_cands;
S32 blk_y;
/*************************************************************************/
/* Related to dimensions of block being searched and pic dimensions */
/*************************************************************************/
S32 blk_wd, blk_ht, blk_size_shift, num_blks_in_row, num_blks_in_pic;
S32 i4_pic_wd, i4_pic_ht, num_blks_in_this_ctb;
S32 num_results_prev_layer;
/*************************************************************************/
/* Size of a basic unit for this layer. For non encode layers, we search */
/* in block sizes of 8x8. For encode layers, though we search 16x16s the */
/* basic unit size is the ctb size. */
/*************************************************************************/
S32 unit_size;
/*************************************************************************/
/* Pointers to context in current and coarser layers */
/*************************************************************************/
layer_ctxt_t *ps_curr_layer, *ps_coarse_layer;
/*************************************************************************/
/* to store mv range per blk, and picture limit, allowed search range */
/* range prms in hpel and qpel units as well */
/*************************************************************************/
range_prms_t s_range_prms_inp, s_range_prms_rec;
range_prms_t s_pic_limit_inp, s_pic_limit_rec, as_mv_limit[MAX_NUM_REF];
/*************************************************************************/
/* These variables are used to track number of references at different */
/* stages of ME. */
/*************************************************************************/
S32 i4_num_ref_fpel, i4_num_ref_before_merge;
S32 i4_num_ref_each_dir, i, i4_num_ref_prev_layer;
S32 lambda_inp = ps_refine_prms->lambda_inp;
/*************************************************************************/
/* When a layer is implicit, it means that it searches on 1 or 2 ref idx */
/* Explicit means it searches on all active ref idx. */
/*************************************************************************/
S32 curr_layer_implicit, prev_layer_implicit;
/*************************************************************************/
/* Variables for loop counts */
/*************************************************************************/
S32 id;
S08 i1_ref_idx;
/*************************************************************************/
/* Input pointer and stride */
/*************************************************************************/
U08 *pu1_inp;
S32 i4_inp_stride;
S32 end_of_frame;
S32 num_sync_units_in_row;
PF_HME_PROJECT_COLOC_CANDT_FXN pf_hme_project_coloc_candt;
ASSERT(ps_refine_prms->i4_layer_id < ps_ctxt->num_layers - 1);
/*************************************************************************/
/* Pointers to current and coarse layer are needed for projection */
/* Pointer to prev layer are needed for other candts like coloc */
/*************************************************************************/
ps_curr_layer = ps_ctxt->ps_curr_descr->aps_layers[ps_refine_prms->i4_layer_id];
ps_coarse_layer = ps_ctxt->ps_curr_descr->aps_layers[ps_refine_prms->i4_layer_id + 1];
num_results_prev_layer = ps_coarse_layer->ps_layer_mvbank->i4_num_mvs_per_ref;
/* Function pointer is selected based on the C vc X86 macro */
fp_get_wt_inp = ((ihevce_me_optimised_function_list_t *)ps_ctxt->pv_me_optimised_function_list)
->pf_get_wt_inp_8x8;
i4_inp_stride = ps_curr_layer->i4_inp_stride;
i4_pic_wd = ps_curr_layer->i4_wd;
i4_pic_ht = ps_curr_layer->i4_ht;
e_search_complexity = ps_refine_prms->e_search_complexity;
end_of_frame = 0;
/* If the previous layer is non-encode layer, then use dyadic projection */
if(0 == ps_ctxt->u1_encode[ps_refine_prms->i4_layer_id + 1])
pf_hme_project_coloc_candt = hme_project_coloc_candt_dyadic;
else
pf_hme_project_coloc_candt = hme_project_coloc_candt;
/* This points to all the initial candts */
ps_search_candts = &as_search_candts[0];
{
e_search_blk_size = BLK_8x8;
blk_wd = blk_ht = 8;
blk_size_shift = 3;
s_mv_update_prms.i4_shift = 0;
/*********************************************************************/
/* In case we do not encode this layer, we search 8x8 with or without*/
/* enable 4x4 SAD. */
/*********************************************************************/
{
S32 i4_mask = (ENABLE_2Nx2N);
e_result_blk_size = BLK_8x8;
if(ps_refine_prms->i4_enable_4x4_part)
{
i4_mask |= (ENABLE_NxN);
e_result_blk_size = BLK_4x4;
s_mv_update_prms.i4_shift = 1;
}
s_search_prms_blk.i4_part_mask = i4_mask;
}
unit_size = blk_wd;
s_search_prms_blk.i4_inp_stride = unit_size;
}
/* This is required to properly update the layer mv bank */
s_mv_update_prms.e_search_blk_size = e_search_blk_size;
s_search_prms_blk.e_blk_size = e_search_blk_size;
/*************************************************************************/
/* If current layer is explicit, then the number of ref frames are to */
/* be same as previous layer. Else it will be 2 */
/*************************************************************************/
i4_num_ref_prev_layer = ps_coarse_layer->ps_layer_mvbank->i4_num_ref;
if(ps_refine_prms->explicit_ref)
{
curr_layer_implicit = 0;
i4_num_ref_fpel = i4_num_ref_prev_layer;
/* 100578 : Using same mv cost fun. for all presets. */
s_search_prms_blk.pf_mv_cost_compute = compute_mv_cost_refine;
}
else
{
i4_num_ref_fpel = 2;
curr_layer_implicit = 1;
{
if(ME_MEDIUM_SPEED > e_me_quality_presets)
{
s_search_prms_blk.pf_mv_cost_compute = compute_mv_cost_implicit;
}
else
{
#if USE_MODIFIED == 1
s_search_prms_blk.pf_mv_cost_compute = compute_mv_cost_implicit_high_speed_modified;
#else
s_search_prms_blk.pf_mv_cost_compute = compute_mv_cost_implicit_high_speed;
#endif
}
}
}
i4_num_ref_fpel = MIN(i4_num_ref_fpel, i4_num_ref_prev_layer);
if(ps_multi_thrd_ctxt->aps_curr_inp_pre_enc[i4_ping_pong]->s_lap_out.i4_pic_type ==
IV_IDR_FRAME ||
ps_multi_thrd_ctxt->aps_curr_inp_pre_enc[i4_ping_pong]->s_lap_out.i4_pic_type == IV_I_FRAME)
{
i4_num_ref_fpel = 1;
}
if(i4_num_ref_prev_layer <= 2)
{
prev_layer_implicit = 1;
curr_layer_implicit = 1;
i4_num_ref_each_dir = 1;
}
else
{
/* It is assumed that we have equal number of references in each dir */
//ASSERT(!(i4_num_ref_prev_layer & 1));
prev_layer_implicit = 0;
i4_num_ref_each_dir = i4_num_ref_prev_layer >> 1;
}
s_mv_update_prms.i4_num_ref = i4_num_ref_fpel;
s_mv_update_prms.i4_num_active_ref_l0 = ps_ctxt->s_frm_prms.u1_num_active_ref_l0;
s_mv_update_prms.i4_num_active_ref_l1 = ps_ctxt->s_frm_prms.u1_num_active_ref_l1;
/* this can be kept to 1 or 2 */
i4_num_ref_before_merge = 2;
i4_num_ref_before_merge = MIN(i4_num_ref_before_merge, i4_num_ref_fpel);
/* Set up place holders to hold the search nodes of each initial candt */
for(i = 0; i < MAX_INIT_CANDTS; i++)
{
ps_search_candts[i].ps_search_node = &ps_ctxt->s_init_search_node[i];
INIT_SEARCH_NODE(ps_search_candts[i].ps_search_node, 0);
}
/* redundant, but doing it here since it is used in pred ctxt init */
ps_candt_zeromv = ps_search_candts[0].ps_search_node;
for(i = 0; i < 3; i++)
{
search_node_t *ps_search_node;
ps_search_node = &as_left_neighbours[i];
INIT_SEARCH_NODE(ps_search_node, 0);
ps_search_node = &as_top_neighbours[i];
INIT_SEARCH_NODE(ps_search_node, 0);
}
INIT_SEARCH_NODE(&as_top_neighbours[3], 0);
/* bottom left node always not available for the blk being searched */
as_left_neighbours[2].u1_is_avail = 0;
/*************************************************************************/
/* Initialize all the search results structure here. We update all the */
/* search results to default values, and configure things like blk sizes */
/*************************************************************************/
if(ps_refine_prms->i4_encode == 0)
{
S32 pred_lx;
search_results_t *ps_search_results;
ps_search_results = &ps_ctxt->s_search_results_8x8;
hme_init_search_results(
ps_search_results,
i4_num_ref_fpel,
ps_refine_prms->i4_num_fpel_results,
ps_refine_prms->i4_num_results_per_part,
e_search_blk_size,
0,
0,
&ps_ctxt->au1_is_past[0]);
for(pred_lx = 0; pred_lx < 2; pred_lx++)
{
hme_init_pred_ctxt_no_encode(
&ps_search_results->as_pred_ctxt[pred_lx],
ps_search_results,
&as_top_neighbours[0],
&as_left_neighbours[0],
&ps_candt_prj_coloc[0],
ps_candt_zeromv,
ps_candt_zeromv,
pred_lx,
lambda_inp,
ps_refine_prms->lambda_q_shift,
&ps_ctxt->apu1_ref_bits_tlu_lc[0],
&ps_ctxt->ai2_ref_scf[0]);
}
}
/*********************************************************************/
/* Initialize the dyn. search range params. for each reference index */
/* in current layer ctxt */
/*********************************************************************/
/* Only for P pic. For P, both are 0, I&B has them mut. exclusive */
if(ps_ctxt->s_frm_prms.is_i_pic == ps_ctxt->s_frm_prms.bidir_enabled)
{
WORD32 ref_ctr;
for(ref_ctr = 0; ref_ctr < s_mv_update_prms.i4_num_ref; ref_ctr++)
{
INIT_DYN_SEARCH_PRMS(
&ps_ctxt->s_coarse_dyn_range_prms
.as_dyn_range_prms[ps_refine_prms->i4_layer_id][ref_ctr],
ps_ctxt->ai4_ref_idx_to_poc_lc[ref_ctr]);
}
}
/* Next set up initial candidates according to a given set of rules. */
/* The number of initial candidates affects the quality of ME in the */
/* case of motion with multiple degrees of freedom. In case of simple */
/* translational motion, a current and a few causal and non causal */
/* candts would suffice. More candidates help to cover more complex */
/* cases like partitions, rotation/zoom, occlusion in/out, fine motion */
/* where multiple ref helps etc. */
/* The candidate choice also depends on the following parameters. */
/* e_search_complexity: SRCH_CX_LOW, SRCH_CX_MED, SRCH_CX_HIGH */
/* Whether we encode or not, and the type of search across reference */
/* i.e. the previous layer may have been explicit/implicit and curr */
/* layer may be explicit/implicit */
/* 0, 0, L, T, projected coloc best always presnt by default */
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(ZERO_MV, e_me_quality_presets);
ps_candt_zeromv = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 0;
ps_candt_zeromv->s_mv.i2_mvx = 0;
ps_candt_zeromv->s_mv.i2_mvy = 0;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(SPATIAL_LEFT0, e_me_quality_presets);
ps_candt_l = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 0;
/* Even in ME_HIGH_SPEED mode, in layer 0, blocks */
/* not at the CTB boundary use the causal T and */
/* not the projected T, although the candidate is */
/* still pointed to by ps_candt_prj_t[0] */
if(ME_MEDIUM_SPEED <= e_me_quality_presets)
{
/* Using Projected top to eliminate sync */
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_TOP0, e_me_quality_presets);
ps_candt_prj_t[0] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
}
else
{
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
SPATIAL_TOP0, e_me_quality_presets);
ps_candt_t = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 0;
}
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_COLOC0, e_me_quality_presets);
ps_candt_prj_coloc[0] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_COLOC1, e_me_quality_presets);
ps_candt_prj_coloc[1] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
if(ME_MEDIUM_SPEED <= e_me_quality_presets)
{
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_TOP_RIGHT0, e_me_quality_presets);
ps_candt_prj_tr[0] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_TOP_LEFT0, e_me_quality_presets);
ps_candt_prj_tl[0] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
}
else
{
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
SPATIAL_TOP_RIGHT0, e_me_quality_presets);
ps_candt_tr = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 0;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
SPATIAL_TOP_LEFT0, e_me_quality_presets);
ps_candt_tl = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 0;
}
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_RIGHT0, e_me_quality_presets);
ps_candt_prj_r[0] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_BOTTOM0, e_me_quality_presets);
ps_candt_prj_b[0] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_BOTTOM_RIGHT0, e_me_quality_presets);
ps_candt_prj_br[0] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_BOTTOM_LEFT0, e_me_quality_presets);
ps_candt_prj_bl[0] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_RIGHT1, e_me_quality_presets);
ps_candt_prj_r[1] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_BOTTOM1, e_me_quality_presets);
ps_candt_prj_b[1] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_BOTTOM_RIGHT1, e_me_quality_presets);
ps_candt_prj_br[1] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_BOTTOM_LEFT1, e_me_quality_presets);
ps_candt_prj_bl[1] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(PROJECTED_TOP1, e_me_quality_presets);
ps_candt_prj_t[1] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_TOP_RIGHT1, e_me_quality_presets);
ps_candt_prj_tr[1] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
id = hme_decide_search_candidate_priority_in_l1_and_l2_me(
PROJECTED_TOP_LEFT1, e_me_quality_presets);
ps_candt_prj_tl[1] = ps_search_candts[id].ps_search_node;
ps_search_candts[id].u1_num_steps_refine = 1;
/*************************************************************************/
/* Now that the candidates have been ordered, to choose the right number */
/* of initial candidates. */
/*************************************************************************/
if(curr_layer_implicit && !prev_layer_implicit)
{
if(e_search_complexity == SEARCH_CX_LOW)
num_init_candts = 7;
else if(e_search_complexity == SEARCH_CX_MED)
num_init_candts = 13;
else if(e_search_complexity == SEARCH_CX_HIGH)
num_init_candts = 18;
else
ASSERT(0);
}
else
{
if(e_search_complexity == SEARCH_CX_LOW)
num_init_candts = 5;
else if(e_search_complexity == SEARCH_CX_MED)
num_init_candts = 11;
else if(e_search_complexity == SEARCH_CX_HIGH)
num_init_candts = 16;
else
ASSERT(0);
}
if(ME_XTREME_SPEED_25 == e_me_quality_presets)
{
num_init_candts = NUM_INIT_SEARCH_CANDS_IN_L1_AND_L2_ME_IN_XS25;
}
/*************************************************************************/
/* The following search parameters are fixed throughout the search across*/
/* all blks. So these are configured outside processing loop */
/*************************************************************************/
s_search_prms_blk.i4_num_init_candts = num_init_candts;
s_search_prms_blk.i4_start_step = 1;
s_search_prms_blk.i4_use_satd = 0;
s_search_prms_blk.i4_num_steps_post_refine = ps_refine_prms->i4_num_steps_post_refine_fpel;
/* we use recon only for encoded layers, otherwise it is not available */
s_search_prms_blk.i4_use_rec = ps_refine_prms->i4_encode & ps_refine_prms->i4_use_rec_in_fpel;
s_search_prms_blk.ps_search_candts = ps_search_candts;
/* We use the same mv_range for all ref. pic. So assign to member 0 */
if(s_search_prms_blk.i4_use_rec)
s_search_prms_blk.aps_mv_range[0] = &s_range_prms_rec;
else
s_search_prms_blk.aps_mv_range[0] = &s_range_prms_inp;
/*************************************************************************/
/* Initialize coordinates. Meaning as follows */
/* blk_x : x coordinate of the 16x16 blk, in terms of number of blks */
/* blk_y : same as above, y coord. */
/* num_blks_in_this_ctb : number of blks in this given ctb that starts */
/* at i4_ctb_x, i4_ctb_y. This may not be 16 at picture boundaries. */
/* i4_ctb_x, i4_ctb_y: pixel coordinate of the ctb realtive to top left */
/* corner of the picture. Always multiple of 64. */
/* blk_id_in_ctb : encode order id of the blk in the ctb. */
/*************************************************************************/
blk_y = 0;
blk_id_in_ctb = 0;
GET_NUM_BLKS_IN_PIC(i4_pic_wd, i4_pic_ht, blk_size_shift, num_blks_in_row, num_blks_in_pic);
/* Get the number of sync units in a row based on encode/non enocde layer */
num_sync_units_in_row = num_blks_in_row;
/*************************************************************************/
/* Picture limit on all 4 sides. This will be used to set mv limits for */
/* every block given its coordinate. Note thsi assumes that the min amt */
/* of padding to right of pic is equal to the blk size. If we go all the */
/* way upto 64x64, then the min padding on right size of picture should */
/* be 64, and also on bottom side of picture. */
/*************************************************************************/
SET_PIC_LIMIT(
s_pic_limit_inp,
ps_curr_layer->i4_pad_x_inp,
ps_curr_layer->i4_pad_y_inp,
ps_curr_layer->i4_wd,
ps_curr_layer->i4_ht,
s_search_prms_blk.i4_num_steps_post_refine);
SET_PIC_LIMIT(
s_pic_limit_rec,
ps_curr_layer->i4_pad_x_rec,
ps_curr_layer->i4_pad_y_rec,
ps_curr_layer->i4_wd,
ps_curr_layer->i4_ht,
s_search_prms_blk.i4_num_steps_post_refine);
/*************************************************************************/
/* set the MV limit per ref. pic. */
/* - P pic. : Based on the config params. */
/* - B/b pic: Based on the Max/Min MV from prev. P and config. param. */
/*************************************************************************/
{
WORD32 ref_ctr;
/* Only for B/b pic. */
if(1 == ps_ctxt->s_frm_prms.bidir_enabled)
{
WORD16 i2_mv_y_per_poc, i2_max_mv_y;
WORD32 cur_poc, ref_poc, abs_poc_diff;
cur_poc = ps_ctxt->i4_curr_poc;
/* Get abs MAX for symmetric search */
i2_mv_y_per_poc = MAX(
ps_ctxt->s_coarse_dyn_range_prms.i2_dyn_max_y_per_poc[ps_refine_prms->i4_layer_id],
(ABS(ps_ctxt->s_coarse_dyn_range_prms
.i2_dyn_min_y_per_poc[ps_refine_prms->i4_layer_id])));
for(ref_ctr = 0; ref_ctr < i4_num_ref_fpel; ref_ctr++)
{
ref_poc = ps_ctxt->ai4_ref_idx_to_poc_lc[ref_ctr];
abs_poc_diff = ABS((cur_poc - ref_poc));
/* Get the cur. max MV based on POC distance */
i2_max_mv_y = i2_mv_y_per_poc * abs_poc_diff;
i2_max_mv_y = MIN(i2_max_mv_y, ps_curr_layer->i2_max_mv_y);
as_mv_limit[ref_ctr].i2_min_x = -ps_curr_layer->i2_max_mv_x;
as_mv_limit[ref_ctr].i2_min_y = -i2_max_mv_y;
as_mv_limit[ref_ctr].i2_max_x = ps_curr_layer->i2_max_mv_x;
as_mv_limit[ref_ctr].i2_max_y = i2_max_mv_y;
}
}
else
{
/* Set the Config. File Params for P pic. */
for(ref_ctr = 0; ref_ctr < i4_num_ref_fpel; ref_ctr++)
{
as_mv_limit[ref_ctr].i2_min_x = -ps_curr_layer->i2_max_mv_x;
as_mv_limit[ref_ctr].i2_min_y = -ps_curr_layer->i2_max_mv_y;
as_mv_limit[ref_ctr].i2_max_x = ps_curr_layer->i2_max_mv_x;
as_mv_limit[ref_ctr].i2_max_y = ps_curr_layer->i2_max_mv_y;
}
}
}
/* EIID: Calculate threshold based on quality preset and/or temporal layers */
if(e_me_quality_presets == ME_MEDIUM_SPEED)
{
i4_threshold_multiplier = 1;
i4_threshold_divider = 4;
}
else if(e_me_quality_presets == ME_HIGH_SPEED)
{
i4_threshold_multiplier = 1;
i4_threshold_divider = 2;
}
else if((e_me_quality_presets == ME_XTREME_SPEED) || (e_me_quality_presets == ME_XTREME_SPEED_25))
{
#if OLD_XTREME_SPEED
/* Hard coding the temporal ID value to 1, if it is older xtreme speed */
i4_temporal_layer = 1;
#endif
if(i4_temporal_layer == 0)
{
i4_threshold_multiplier = 3;
i4_threshold_divider = 4;
}
else if(i4_temporal_layer == 1)
{
i4_threshold_multiplier = 3;
i4_threshold_divider = 4;
}
else if(i4_temporal_layer == 2)
{
i4_threshold_multiplier = 1;
i4_threshold_divider = 1;
}
else
{
i4_threshold_multiplier = 5;
i4_threshold_divider = 4;
}
}
else if(e_me_quality_presets == ME_HIGH_QUALITY)
{
i4_threshold_multiplier = 1;
i4_threshold_divider = 1;
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/* START OF THE CORE LOOP */
/* If Encode is 0, then we just loop over each blk */
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
while(0 == end_of_frame)
{
job_queue_t *ps_job;
ihevce_ed_blk_t *ps_ed_blk_ctxt_curr_row; //EIID
WORD32 i4_ctb_row_ctr; //counter to calculate CTB row counter. It's (row_ctr /4)
WORD32 i4_num_ctbs_in_row = (num_blks_in_row + 3) / 4; //calculations verified for L1 only
//+3 to get ceil values when divided by 4
WORD32 i4_num_4x4_blocks_in_ctb_at_l1 =
8 * 8; //considering CTB size 32x32 at L1. hardcoded for now
//if there is variable for ctb size use that and this variable can be derived
WORD32 offset_val, check_dep_pos, set_dep_pos;
void *pv_hme_dep_mngr;
ihevce_ed_ctb_l1_t *ps_ed_ctb_l1_row;
/* Get the current layer HME Dep Mngr */
/* Note : Use layer_id - 1 in HME layers */
pv_hme_dep_mngr = ppv_dep_mngr_hme_sync[ps_refine_prms->i4_layer_id - 1];
/* Get the current row from the job queue */
ps_job = (job_queue_t *)ihevce_pre_enc_grp_get_next_job(
ps_multi_thrd_ctxt, lyr_job_type, 1, i4_ping_pong);
/* If all rows are done, set the end of process flag to 1, */
/* and the current row to -1 */
if(NULL == ps_job)
{
blk_y = -1;
end_of_frame = 1;
continue;
}
if(1 == ps_ctxt->s_frm_prms.is_i_pic)
{
/* set the output dependency of current row */
ihevce_pre_enc_grp_job_set_out_dep(ps_multi_thrd_ctxt, ps_job, i4_ping_pong);
continue;
}
blk_y = ps_job->s_job_info.s_me_job_info.i4_vert_unit_row_no;
blk_x = 0;
i4_ctb_x = 0;
/* wait for Corresponding Pre intra Job to be completed */
if(1 == ps_refine_prms->i4_layer_id)
{
volatile UWORD32 i4_l1_done;
volatile UWORD32 *pi4_l1_done;
pi4_l1_done = (volatile UWORD32 *)&ps_multi_thrd_ctxt
->aai4_l1_pre_intra_done[i4_ping_pong][blk_y >> 2];
i4_l1_done = *pi4_l1_done;
while(!i4_l1_done)
{
i4_l1_done = *pi4_l1_done;
}
}
/* Set Variables for Dep. Checking and Setting */
set_dep_pos = blk_y + 1;
if(blk_y > 0)
{
offset_val = 2;
check_dep_pos = blk_y - 1;
}
else
{
/* First row should run without waiting */
offset_val = -1;
check_dep_pos = 0;
}
/* EIID: calculate ed_blk_ctxt pointer for current row */
/* valid for only layer-1. not varified and used for other layers */
i4_ctb_row_ctr = blk_y / 4;
ps_ed_blk_ctxt_curr_row =
ps_ctxt->ps_ed_blk + (i4_ctb_row_ctr * i4_num_ctbs_in_row *
i4_num_4x4_blocks_in_ctb_at_l1); //valid for L1 only
ps_ed_ctb_l1_row = ps_ctxt->ps_ed_ctb_l1 + (i4_ctb_row_ctr * i4_num_ctbs_in_row);
/* if non-encode layer then i4_ctb_x will be same as blk_x */
/* loop over all the units is a row */
for(; i4_ctb_x < num_sync_units_in_row; i4_ctb_x++)
{
ihevce_ed_blk_t *ps_ed_blk_ctxt_curr_ctb; //EIDD
ihevce_ed_ctb_l1_t *ps_ed_ctb_l1_curr;
WORD32 i4_ctb_blk_ctr = i4_ctb_x / 4;
/* Wait till top row block is processed */
/* Currently checking till top right block*/
/* Disabled since all candidates, except for */
/* L and C, are projected from the coarser layer, */
/* only in ME_HIGH_SPEED mode */
if((ME_MEDIUM_SPEED > e_me_quality_presets))
{
if(i4_ctb_x < (num_sync_units_in_row - 1))
{
ihevce_dmgr_chk_row_row_sync(
pv_hme_dep_mngr,
i4_ctb_x,
offset_val,
check_dep_pos,
0, /* Col Tile No. : Not supported in PreEnc*/
ps_ctxt->thrd_id);
}
}
{
/* for non encoder layer only one block is processed */
num_blks_in_this_ctb = 1;
}
/* EIID: derive ed_ctxt ptr for current CTB */
ps_ed_blk_ctxt_curr_ctb =
ps_ed_blk_ctxt_curr_row +
(i4_ctb_blk_ctr *
i4_num_4x4_blocks_in_ctb_at_l1); //currently valid for l1 layer only
ps_ed_ctb_l1_curr = ps_ed_ctb_l1_row + i4_ctb_blk_ctr;
/* loop over all the blocks in CTB will always be 1 */
for(blk_id_in_ctb = 0; blk_id_in_ctb < num_blks_in_this_ctb; blk_id_in_ctb++)
{
{
/* non encode layer */
blk_x = i4_ctb_x;
blk_id_in_full_ctb = 0;
s_search_prms_blk.i4_cu_x_off = s_search_prms_blk.i4_cu_y_off = 0;
}
/* get the current input blk point */
pos_x = blk_x << blk_size_shift;
pos_y = blk_y << blk_size_shift;
pu1_inp = ps_curr_layer->pu1_inp + pos_x + (pos_y * i4_inp_stride);
/*********************************************************************/
/* replicate the inp buffer at blk or ctb level for each ref id, */
/* Instead of searching with wk * ref(k), we search with Ik = I / wk */
/* thereby avoiding a bloat up of memory. If we did all references */
/* weighted pred, we will end up with a duplicate copy of each ref */
/* at each layer, since we need to preserve the original reference. */
/* ToDo: Need to observe performance with this mechanism and compare */
/* with case where ref is weighted. */
/*********************************************************************/
if(blk_id_in_ctb == 0)
{
fp_get_wt_inp(
ps_curr_layer,
&ps_ctxt->s_wt_pred,
unit_size,
pos_x,
pos_y,
unit_size,
ps_ctxt->num_ref_future + ps_ctxt->num_ref_past,
ps_ctxt->i4_wt_pred_enable_flag);
}
s_search_prms_blk.i4_x_off = blk_x << blk_size_shift;
s_search_prms_blk.i4_y_off = blk_y << blk_size_shift;
/* Select search results from a suitable search result in the context */
{
ps_search_results = &ps_ctxt->s_search_results_8x8;
}
s_search_prms_blk.ps_search_results = ps_search_results;
/* RESET ALL SEARCH RESULTS FOR THE NEW BLK */
hme_reset_search_results(
ps_search_results, s_search_prms_blk.i4_part_mask, MV_RES_FPEL);
/* Loop across different Ref IDx */
for(i1_ref_idx = 0; i1_ref_idx < i4_num_ref_fpel; i1_ref_idx++)
{
S32 next_blk_offset = (e_search_blk_size == BLK_16x16) ? 22 : 12;
S32 prev_blk_offset = 6;
S32 resultid;
/*********************************************************************/
/* For every blk in the picture, the search range needs to be derived*/
/* Any blk can have any mv, but practical search constraints are */
/* imposed by the picture boundary and amt of padding. */
/*********************************************************************/
/* MV limit is different based on ref. PIC */
hme_derive_search_range(
&s_range_prms_inp,
&s_pic_limit_inp,
&as_mv_limit[i1_ref_idx],
pos_x,
pos_y,
blk_wd,
blk_ht);
hme_derive_search_range(
&s_range_prms_rec,
&s_pic_limit_rec,
&as_mv_limit[i1_ref_idx],
pos_x,
pos_y,
blk_wd,
blk_ht);
s_search_prms_blk.i1_ref_idx = i1_ref_idx;
ps_candt_zeromv->i1_ref_idx = i1_ref_idx;
i4_num_srch_cands = 1;
if(1 != ps_refine_prms->i4_layer_id)
{
S32 x, y;
x = gau1_encode_to_raster_x[blk_id_in_full_ctb];
y = gau1_encode_to_raster_y[blk_id_in_full_ctb];
if(ME_MEDIUM_SPEED > e_me_quality_presets)
{
hme_get_spatial_candt(
ps_curr_layer,
e_search_blk_size,
blk_x,
blk_y,
i1_ref_idx,
&as_top_neighbours[0],
&as_left_neighbours[0],
0,
((ps_refine_prms->i4_encode) ? gau1_cu_tr_valid[y][x] : 1),
0,
ps_refine_prms->i4_encode);
*ps_candt_tr = as_top_neighbours[3];
*ps_candt_t = as_top_neighbours[1];
*ps_candt_tl = as_top_neighbours[0];
i4_num_srch_cands += 3;
}
else
{
layer_mv_t *ps_layer_mvbank = ps_curr_layer->ps_layer_mvbank;
S32 i4_blk_size1 = gau1_blk_size_to_wd[ps_layer_mvbank->e_blk_size];
S32 i4_blk_size2 = gau1_blk_size_to_wd[e_search_blk_size];
search_node_t *ps_search_node;
S32 i4_offset, blk_x_temp = blk_x, blk_y_temp = blk_y;
hme_mv_t *ps_mv, *ps_mv_base;
S08 *pi1_ref_idx, *pi1_ref_idx_base;
S32 jump = 1, mvs_in_blk, mvs_in_row;
S32 shift = (ps_refine_prms->i4_encode ? 2 : 0);
if(i4_blk_size1 != i4_blk_size2)
{
blk_x_temp <<= 1;
blk_y_temp <<= 1;
jump = 2;
if((i4_blk_size1 << 2) == i4_blk_size2)
{
blk_x_temp <<= 1;
blk_y_temp <<= 1;
jump = 4;
}
}
mvs_in_blk = ps_layer_mvbank->i4_num_mvs_per_blk;
mvs_in_row = ps_layer_mvbank->i4_num_mvs_per_row;
/* Adjust teh blk coord to point to top left locn */
blk_x_temp -= 1;
blk_y_temp -= 1;
/* Pick up the mvs from the location */
i4_offset = (blk_x_temp * ps_layer_mvbank->i4_num_mvs_per_blk);
i4_offset += (ps_layer_mvbank->i4_num_mvs_per_row * blk_y_temp);
ps_mv = ps_layer_mvbank->ps_mv + i4_offset;
pi1_ref_idx = ps_layer_mvbank->pi1_ref_idx + i4_offset;
ps_mv += (i1_ref_idx * ps_layer_mvbank->i4_num_mvs_per_ref);
pi1_ref_idx += (i1_ref_idx * ps_layer_mvbank->i4_num_mvs_per_ref);
ps_mv_base = ps_mv;
pi1_ref_idx_base = pi1_ref_idx;
ps_search_node = &as_left_neighbours[0];
ps_mv = ps_mv_base + mvs_in_row;
pi1_ref_idx = pi1_ref_idx_base + mvs_in_row;
COPY_MV_TO_SEARCH_NODE(
ps_search_node, ps_mv, pi1_ref_idx, i1_ref_idx, shift);
i4_num_srch_cands++;
}
}
else
{
S32 x, y;
x = gau1_encode_to_raster_x[blk_id_in_full_ctb];
y = gau1_encode_to_raster_y[blk_id_in_full_ctb];
if(ME_MEDIUM_SPEED > e_me_quality_presets)
{
hme_get_spatial_candt_in_l1_me(
ps_curr_layer,
e_search_blk_size,
blk_x,
blk_y,
i1_ref_idx,
!ps_search_results->pu1_is_past[i1_ref_idx],
&as_top_neighbours[0],
&as_left_neighbours[0],
0,
((ps_refine_prms->i4_encode) ? gau1_cu_tr_valid[y][x] : 1),
0,
ps_ctxt->s_frm_prms.u1_num_active_ref_l0,
ps_ctxt->s_frm_prms.u1_num_active_ref_l1);
*ps_candt_tr = as_top_neighbours[3];
*ps_candt_t = as_top_neighbours[1];
*ps_candt_tl = as_top_neighbours[0];
i4_num_srch_cands += 3;
}
else
{
layer_mv_t *ps_layer_mvbank = ps_curr_layer->ps_layer_mvbank;
S32 i4_blk_size1 = gau1_blk_size_to_wd[ps_layer_mvbank->e_blk_size];
S32 i4_blk_size2 = gau1_blk_size_to_wd[e_search_blk_size];
S32 i4_mv_pos_in_implicit_array;
search_node_t *ps_search_node;
S32 i4_offset, blk_x_temp = blk_x, blk_y_temp = blk_y;
hme_mv_t *ps_mv, *ps_mv_base;
S08 *pi1_ref_idx, *pi1_ref_idx_base;
S32 jump = 1, mvs_in_blk, mvs_in_row;
S32 shift = (ps_refine_prms->i4_encode ? 2 : 0);
U08 u1_pred_dir = !ps_search_results->pu1_is_past[i1_ref_idx];
S32 i4_num_results_in_given_dir =
((u1_pred_dir == 1) ? (ps_layer_mvbank->i4_num_mvs_per_ref *
ps_ctxt->s_frm_prms.u1_num_active_ref_l1)
: (ps_layer_mvbank->i4_num_mvs_per_ref *
ps_ctxt->s_frm_prms.u1_num_active_ref_l0));
if(i4_blk_size1 != i4_blk_size2)
{
blk_x_temp <<= 1;
blk_y_temp <<= 1;
jump = 2;
if((i4_blk_size1 << 2) == i4_blk_size2)
{
blk_x_temp <<= 1;
blk_y_temp <<= 1;
jump = 4;
}
}
mvs_in_blk = ps_layer_mvbank->i4_num_mvs_per_blk;
mvs_in_row = ps_layer_mvbank->i4_num_mvs_per_row;
/* Adjust teh blk coord to point to top left locn */
blk_x_temp -= 1;
blk_y_temp -= 1;
/* Pick up the mvs from the location */
i4_offset = (blk_x_temp * ps_layer_mvbank->i4_num_mvs_per_blk);
i4_offset += (ps_layer_mvbank->i4_num_mvs_per_row * blk_y_temp);
i4_offset +=
((u1_pred_dir == 1) ? (ps_layer_mvbank->i4_num_mvs_per_ref *
ps_ctxt->s_frm_prms.u1_num_active_ref_l0)
: 0);
ps_mv = ps_layer_mvbank->ps_mv + i4_offset;
pi1_ref_idx = ps_layer_mvbank->pi1_ref_idx + i4_offset;
ps_mv_base = ps_mv;
pi1_ref_idx_base = pi1_ref_idx;
{
/* ps_mv and pi1_ref_idx now point to the top left locn */
ps_search_node = &as_left_neighbours[0];
ps_mv = ps_mv_base + mvs_in_row;
pi1_ref_idx = pi1_ref_idx_base + mvs_in_row;
i4_mv_pos_in_implicit_array =
hme_find_pos_of_implicitly_stored_ref_id(
pi1_ref_idx, i1_ref_idx, 0, i4_num_results_in_given_dir);
if(-1 != i4_mv_pos_in_implicit_array)
{
COPY_MV_TO_SEARCH_NODE(
ps_search_node,
&ps_mv[i4_mv_pos_in_implicit_array],
&pi1_ref_idx[i4_mv_pos_in_implicit_array],
i1_ref_idx,
shift);
}
else
{
ps_search_node->u1_is_avail = 0;
ps_search_node->s_mv.i2_mvx = 0;
ps_search_node->s_mv.i2_mvy = 0;
ps_search_node->i1_ref_idx = i1_ref_idx;
}
i4_num_srch_cands++;
}
}
}
*ps_candt_l = as_left_neighbours[0];
/* when 16x16 is searched in an encode layer, and the prev layer */
/* stores results for 4x4 blks, we project 5 candts corresponding */
/* to (2,2), (2,14), (14,2), 14,14) and 2nd best of (2,2) */
/* However in other cases, only 2,2 best and 2nd best reqd */
resultid = 0;
pf_hme_project_coloc_candt(
ps_candt_prj_coloc[0],
ps_curr_layer,
ps_coarse_layer,
pos_x + 2,
pos_y + 2,
i1_ref_idx,
resultid);
i4_num_srch_cands++;
resultid = 1;
if(num_results_prev_layer > 1)
{
pf_hme_project_coloc_candt(
ps_candt_prj_coloc[1],
ps_curr_layer,
ps_coarse_layer,
pos_x + 2,
pos_y + 2,
i1_ref_idx,
resultid);
i4_num_srch_cands++;
}
resultid = 0;
if(ME_MEDIUM_SPEED <= e_me_quality_presets)
{
pf_hme_project_coloc_candt(
ps_candt_prj_t[0],
ps_curr_layer,
ps_coarse_layer,
pos_x,
pos_y - prev_blk_offset,
i1_ref_idx,
resultid);
i4_num_srch_cands++;
}
{
pf_hme_project_coloc_candt(
ps_candt_prj_br[0],
ps_curr_layer,
ps_coarse_layer,
pos_x + next_blk_offset,
pos_y + next_blk_offset,
i1_ref_idx,
resultid);
pf_hme_project_coloc_candt(
ps_candt_prj_bl[0],
ps_curr_layer,
ps_coarse_layer,
pos_x - prev_blk_offset,
pos_y + next_blk_offset,
i1_ref_idx,
resultid);
pf_hme_project_coloc_candt(
ps_candt_prj_r[0],
ps_curr_layer,
ps_coarse_layer,
pos_x + next_blk_offset,
pos_y,
i1_ref_idx,
resultid);
pf_hme_project_coloc_candt(
ps_candt_prj_b[0],
ps_curr_layer,
ps_coarse_layer,
pos_x,
pos_y + next_blk_offset,
i1_ref_idx,
resultid);
i4_num_srch_cands += 4;
if(ME_MEDIUM_SPEED <= e_me_quality_presets)
{
pf_hme_project_coloc_candt(
ps_candt_prj_tr[0],
ps_curr_layer,
ps_coarse_layer,
pos_x + next_blk_offset,
pos_y - prev_blk_offset,
i1_ref_idx,
resultid);
pf_hme_project_coloc_candt(
ps_candt_prj_tl[0],
ps_curr_layer,
ps_coarse_layer,
pos_x - prev_blk_offset,
pos_y - prev_blk_offset,
i1_ref_idx,
resultid);
i4_num_srch_cands += 2;
}
}
if((num_results_prev_layer > 1) && (e_search_complexity >= SEARCH_CX_MED))
{
resultid = 1;
pf_hme_project_coloc_candt(
ps_candt_prj_br[1],
ps_curr_layer,
ps_coarse_layer,
pos_x + next_blk_offset,
pos_y + next_blk_offset,
i1_ref_idx,
resultid);
pf_hme_project_coloc_candt(
ps_candt_prj_bl[1],
ps_curr_layer,
ps_coarse_layer,
pos_x - prev_blk_offset,
pos_y + next_blk_offset,
i1_ref_idx,
resultid);
pf_hme_project_coloc_candt(
ps_candt_prj_r[1],
ps_curr_layer,
ps_coarse_layer,
pos_x + next_blk_offset,
pos_y,
i1_ref_idx,
resultid);
pf_hme_project_coloc_candt(
ps_candt_prj_b[1],
ps_curr_layer,
ps_coarse_layer,
pos_x,
pos_y + next_blk_offset,
i1_ref_idx,
resultid);
i4_num_srch_cands += 4;
pf_hme_project_coloc_candt(
ps_candt_prj_tr[1],
ps_curr_layer,
ps_coarse_layer,
pos_x + next_blk_offset,
pos_y - prev_blk_offset,
i1_ref_idx,
resultid);
pf_hme_project_coloc_candt(
ps_candt_prj_tl[1],
ps_curr_layer,
ps_coarse_layer,
pos_x - prev_blk_offset,
pos_y - prev_blk_offset,
i1_ref_idx,
resultid);
pf_hme_project_coloc_candt(
ps_candt_prj_t[1],
ps_curr_layer,
ps_coarse_layer,
pos_x,
pos_y - prev_blk_offset,
i1_ref_idx,
resultid);
i4_num_srch_cands += 3;
}
/* Note this block also clips the MV range for all candidates */
#ifdef _DEBUG
{
S32 candt;
range_prms_t *ps_range_prms;
S32 num_ref_valid = ps_ctxt->num_ref_future + ps_ctxt->num_ref_past;
for(candt = 0; candt < i4_num_srch_cands; candt++)
{
search_node_t *ps_search_node;
ps_search_node =
s_search_prms_blk.ps_search_candts[candt].ps_search_node;
ps_range_prms = s_search_prms_blk.aps_mv_range[0];
if((ps_search_node->i1_ref_idx >= num_ref_valid) ||
(ps_search_node->i1_ref_idx < 0))
{
ASSERT(0);
}
}
}
#endif
{
S32 srch_cand;
S32 num_unique_nodes = 0;
S32 num_nodes_searched = 0;
S32 num_best_cand = 0;
S08 i1_grid_enable = 0;
search_node_t as_best_two_proj_node[TOT_NUM_PARTS * 2];
/* has list of valid partition to search terminated by -1 */
S32 ai4_valid_part_ids[TOT_NUM_PARTS + 1];
S32 center_x;
S32 center_y;
/* indicates if the centre point of grid needs to be explicitly added for search */
S32 add_centre = 0;
memset(au4_unique_node_map, 0, sizeof(au4_unique_node_map));
center_x = ps_candt_prj_coloc[0]->s_mv.i2_mvx;
center_y = ps_candt_prj_coloc[0]->s_mv.i2_mvy;
for(srch_cand = 0;
(srch_cand < i4_num_srch_cands) &&
(num_unique_nodes <= s_search_prms_blk.i4_num_init_candts);
srch_cand++)
{
search_node_t s_search_node_temp =
s_search_prms_blk.ps_search_candts[srch_cand].ps_search_node[0];
s_search_node_temp.i1_ref_idx = i1_ref_idx; //TEMP FIX;
/* Clip the motion vectors as well here since after clipping
two candidates can become same and they will be removed during deduplication */
CLIP_MV_WITHIN_RANGE(
s_search_node_temp.s_mv.i2_mvx,
s_search_node_temp.s_mv.i2_mvy,
s_search_prms_blk.aps_mv_range[0],
ps_refine_prms->i4_num_steps_fpel_refine,
ps_refine_prms->i4_num_steps_hpel_refine,
ps_refine_prms->i4_num_steps_qpel_refine);
/* PT_C */
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
num_nodes_searched += 1;
}
num_unique_nodes =
MIN(num_unique_nodes, s_search_prms_blk.i4_num_init_candts);
/* If number of candidates projected/number of candidates to be refined are more than 2,
then filter out and choose the best two here */
if(num_unique_nodes >= 2)
{
S32 num_results;
S32 cnt;
S32 *pi4_valid_part_ids;
s_search_prms_blk.ps_search_nodes = &as_unique_search_nodes[0];
s_search_prms_blk.i4_num_search_nodes = num_unique_nodes;
pi4_valid_part_ids = &ai4_valid_part_ids[0];
/* pi4_valid_part_ids is updated inside */
hme_pred_search_no_encode(
&s_search_prms_blk,
ps_curr_layer,
&ps_ctxt->s_wt_pred,
pi4_valid_part_ids,
1,
e_me_quality_presets,
i1_grid_enable,
(ihevce_me_optimised_function_list_t *)
ps_ctxt->pv_me_optimised_function_list
);
num_best_cand = 0;
cnt = 0;
num_results = ps_search_results->u1_num_results_per_part;
while((id = pi4_valid_part_ids[cnt++]) >= 0)
{
num_results =
MIN(ps_refine_prms->pu1_num_best_results[id], num_results);
for(i = 0; i < num_results; i++)
{
search_node_t s_search_node_temp;
s_search_node_temp =
*(ps_search_results->aps_part_results[i1_ref_idx][id] + i);
if(s_search_node_temp.i1_ref_idx >= 0)
{
INSERT_NEW_NODE_NOMAP(
as_best_two_proj_node,
num_best_cand,
s_search_node_temp,
0);
}
}
}
}
else
{
add_centre = 1;
num_best_cand = num_unique_nodes;
as_best_two_proj_node[0] = as_unique_search_nodes[0];
}
num_unique_nodes = 0;
num_nodes_searched = 0;
if(1 == num_best_cand)
{
search_node_t s_search_node_temp = as_best_two_proj_node[0];
S16 i2_mv_x = s_search_node_temp.s_mv.i2_mvx;
S16 i2_mv_y = s_search_node_temp.s_mv.i2_mvy;
S08 i1_ref_idx = s_search_node_temp.i1_ref_idx;
i1_grid_enable = 1;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvx = i2_mv_x - 1;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvy = i2_mv_y - 1;
as_unique_search_nodes[num_unique_nodes++].i1_ref_idx = i1_ref_idx;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvx = i2_mv_x;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvy = i2_mv_y - 1;
as_unique_search_nodes[num_unique_nodes++].i1_ref_idx = i1_ref_idx;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvx = i2_mv_x + 1;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvy = i2_mv_y - 1;
as_unique_search_nodes[num_unique_nodes++].i1_ref_idx = i1_ref_idx;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvx = i2_mv_x - 1;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvy = i2_mv_y;
as_unique_search_nodes[num_unique_nodes++].i1_ref_idx = i1_ref_idx;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvx = i2_mv_x + 1;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvy = i2_mv_y;
as_unique_search_nodes[num_unique_nodes++].i1_ref_idx = i1_ref_idx;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvx = i2_mv_x - 1;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvy = i2_mv_y + 1;
as_unique_search_nodes[num_unique_nodes++].i1_ref_idx = i1_ref_idx;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvx = i2_mv_x;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvy = i2_mv_y + 1;
as_unique_search_nodes[num_unique_nodes++].i1_ref_idx = i1_ref_idx;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvx = i2_mv_x + 1;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvy = i2_mv_y + 1;
as_unique_search_nodes[num_unique_nodes++].i1_ref_idx = i1_ref_idx;
if(add_centre)
{
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvx = i2_mv_x;
as_unique_search_nodes[num_unique_nodes].s_mv.i2_mvy = i2_mv_y;
as_unique_search_nodes[num_unique_nodes++].i1_ref_idx = i1_ref_idx;
}
}
else
{
/* For the candidates where refinement was required, choose the best two */
for(srch_cand = 0; srch_cand < num_best_cand; srch_cand++)
{
search_node_t s_search_node_temp = as_best_two_proj_node[srch_cand];
WORD32 mv_x = s_search_node_temp.s_mv.i2_mvx;
WORD32 mv_y = s_search_node_temp.s_mv.i2_mvy;
/* Because there may not be two best unique candidates (because of clipping),
second best candidate can be uninitialized, ignore that */
if(s_search_node_temp.s_mv.i2_mvx == INTRA_MV ||
s_search_node_temp.i1_ref_idx < 0)
{
num_nodes_searched++;
continue;
}
/* PT_C */
/* Since the center point has already be evaluated and best results are persistent,
it will not be evaluated again */
if(add_centre) /* centre point added explicitly again if search results is not updated */
{
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
}
/* PT_L */
s_search_node_temp.s_mv.i2_mvx = mv_x - 1;
s_search_node_temp.s_mv.i2_mvy = mv_y;
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
/* PT_T */
s_search_node_temp.s_mv.i2_mvx = mv_x;
s_search_node_temp.s_mv.i2_mvy = mv_y - 1;
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
/* PT_R */
s_search_node_temp.s_mv.i2_mvx = mv_x + 1;
s_search_node_temp.s_mv.i2_mvy = mv_y;
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
/* PT_B */
s_search_node_temp.s_mv.i2_mvx = mv_x;
s_search_node_temp.s_mv.i2_mvy = mv_y + 1;
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
/* PT_TL */
s_search_node_temp.s_mv.i2_mvx = mv_x - 1;
s_search_node_temp.s_mv.i2_mvy = mv_y - 1;
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
/* PT_TR */
s_search_node_temp.s_mv.i2_mvx = mv_x + 1;
s_search_node_temp.s_mv.i2_mvy = mv_y - 1;
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
/* PT_BL */
s_search_node_temp.s_mv.i2_mvx = mv_x - 1;
s_search_node_temp.s_mv.i2_mvy = mv_y + 1;
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
/* PT_BR */
s_search_node_temp.s_mv.i2_mvx = mv_x + 1;
s_search_node_temp.s_mv.i2_mvy = mv_y + 1;
INSERT_NEW_NODE(
as_unique_search_nodes,
num_unique_nodes,
s_search_node_temp,
0,
au4_unique_node_map,
center_x,
center_y,
1);
}
}
s_search_prms_blk.ps_search_nodes = &as_unique_search_nodes[0];
s_search_prms_blk.i4_num_search_nodes = num_unique_nodes;
/*****************************************************************/
/* Call the search algorithm, this includes: */
/* Pre-Search-Refinement (for coarse candts) */
/* Search on each candidate */
/* Post Search Refinement on winners/other new candidates */
/*****************************************************************/
hme_pred_search_no_encode(
&s_search_prms_blk,
ps_curr_layer,
&ps_ctxt->s_wt_pred,
ai4_valid_part_ids,
0,
e_me_quality_presets,
i1_grid_enable,
(ihevce_me_optimised_function_list_t *)
ps_ctxt->pv_me_optimised_function_list);
i1_grid_enable = 0;
}
}
/* for non encode layer update MV and end processing for block */
{
WORD32 i4_ref_id, min_cost = 0x7fffffff, min_sad = 0;
search_node_t *ps_search_node;
/* now update the reqd results back to the layer mv bank. */
if(1 == ps_refine_prms->i4_layer_id)
{
hme_update_mv_bank_in_l1_me(
ps_search_results,
ps_curr_layer->ps_layer_mvbank,
blk_x,
blk_y,
&s_mv_update_prms);
}
else
{
hme_update_mv_bank_noencode(
ps_search_results,
ps_curr_layer->ps_layer_mvbank,
blk_x,
blk_y,
&s_mv_update_prms);
}
/* UPDATE the MIN and MAX MVs for Dynamical Search Range for each ref. pic. */
/* Only for P pic. For P, both are 0, I&B has them mut. exclusive */
if(ps_ctxt->s_frm_prms.is_i_pic == ps_ctxt->s_frm_prms.bidir_enabled)
{
WORD32 i4_j;
layer_mv_t *ps_layer_mv = ps_curr_layer->ps_layer_mvbank;
//if (ps_layer_mv->e_blk_size == s_mv_update_prms.e_search_blk_size)
/* Not considering this for Dyn. Search Update */
{
for(i4_ref_id = 0; i4_ref_id < (S32)s_mv_update_prms.i4_num_ref;
i4_ref_id++)
{
ps_search_node =
ps_search_results->aps_part_results[i4_ref_id][PART_ID_2Nx2N];
for(i4_j = 0; i4_j < ps_layer_mv->i4_num_mvs_per_ref; i4_j++)
{
hme_update_dynamic_search_params(
&ps_ctxt->s_coarse_dyn_range_prms
.as_dyn_range_prms[ps_refine_prms->i4_layer_id]
[i4_ref_id],
ps_search_node->s_mv.i2_mvy);
ps_search_node++;
}
}
}
}
if(1 == ps_refine_prms->i4_layer_id)
{
WORD32 wt_pred_val, log_wt_pred_val;
WORD32 ref_id_of_nearest_poc = 0;
WORD32 max_val = 0x7fffffff;
WORD32 max_l0_val = 0x7fffffff;
WORD32 max_l1_val = 0x7fffffff;
WORD32 cur_val;
WORD32 i4_local_weighted_sad, i4_local_cost_weighted_pred;
WORD32 bestl0_sad = 0x7fffffff;
WORD32 bestl1_sad = 0x7fffffff;
search_node_t *ps_best_l0_blk = NULL, *ps_best_l1_blk = NULL;
for(i4_ref_id = 0; i4_ref_id < (S32)s_mv_update_prms.i4_num_ref;
i4_ref_id++)
{
wt_pred_val = ps_ctxt->s_wt_pred.a_wpred_wt[i4_ref_id];
log_wt_pred_val = ps_ctxt->s_wt_pred.wpred_log_wdc;
ps_search_node =
ps_search_results->aps_part_results[i4_ref_id][PART_ID_2Nx2N];
i4_local_weighted_sad = ((ps_search_node->i4_sad * wt_pred_val) +
((1 << log_wt_pred_val) >> 1)) >>
log_wt_pred_val;
i4_local_cost_weighted_pred =
i4_local_weighted_sad +
(ps_search_node->i4_tot_cost - ps_search_node->i4_sad);
//the loop is redundant as the results are already sorted based on total cost
//for (i4_j = 0; i4_j < ps_curr_layer->ps_layer_mvbank->i4_num_mvs_per_ref; i4_j++)
{
if(i4_local_cost_weighted_pred < min_cost)
{
min_cost = i4_local_cost_weighted_pred;
min_sad = i4_local_weighted_sad;
}
}
/* For P frame, calculate the nearest poc which is either P or I frame*/
if(ps_ctxt->s_frm_prms.is_i_pic == ps_ctxt->s_frm_prms.bidir_enabled)
{
if(-1 != ps_coarse_layer->ai4_ref_id_to_poc_lc[i4_ref_id])
{
cur_val =
ABS(ps_ctxt->i4_curr_poc -
ps_coarse_layer->ai4_ref_id_to_poc_lc[i4_ref_id]);
if(cur_val < max_val)
{
max_val = cur_val;
ref_id_of_nearest_poc = i4_ref_id;
}
}
}
}
/*Store me cost wrt. to past frame only for P frame */
if(ps_ctxt->s_frm_prms.is_i_pic == ps_ctxt->s_frm_prms.bidir_enabled)
{
if(-1 != ps_coarse_layer->ai4_ref_id_to_poc_lc[ref_id_of_nearest_poc])
{
WORD16 i2_mvx, i2_mvy;
WORD32 i4_diff_col_ctr = blk_x - (i4_ctb_blk_ctr * 4);
WORD32 i4_diff_row_ctr = blk_y - (i4_ctb_row_ctr * 4);
WORD32 z_scan_idx =
gau1_raster_scan_to_ctb[i4_diff_row_ctr][i4_diff_col_ctr];
WORD32 wt, log_wt;
/*ASSERT((ps_ctxt->i4_curr_poc - ps_coarse_layer->ai4_ref_id_to_poc_lc[ref_id_of_nearest_poc])
<= (1 + ps_ctxt->num_b_frms));*/
/*obtain mvx and mvy */
i2_mvx =
ps_search_results
->aps_part_results[ref_id_of_nearest_poc][PART_ID_2Nx2N]
->s_mv.i2_mvx;
i2_mvy =
ps_search_results
->aps_part_results[ref_id_of_nearest_poc][PART_ID_2Nx2N]
->s_mv.i2_mvy;
/*register the min cost for l1 me in blk context */
wt = ps_ctxt->s_wt_pred.a_wpred_wt[ref_id_of_nearest_poc];
log_wt = ps_ctxt->s_wt_pred.wpred_log_wdc;
/*register the min cost for l1 me in blk context */
ps_ed_ctb_l1_curr->i4_sad_me_for_ref[z_scan_idx >> 2] =
((ps_search_results
->aps_part_results[ref_id_of_nearest_poc][PART_ID_2Nx2N]
->i4_sad *
wt) +
((1 << log_wt) >> 1)) >>
log_wt;
ps_ed_ctb_l1_curr->i4_sad_cost_me_for_ref[z_scan_idx >> 2] =
ps_ed_ctb_l1_curr->i4_sad_me_for_ref[z_scan_idx >> 2] +
(ps_search_results
->aps_part_results[ref_id_of_nearest_poc][PART_ID_2Nx2N]
->i4_tot_cost -
ps_search_results
->aps_part_results[ref_id_of_nearest_poc][PART_ID_2Nx2N]
->i4_sad);
/*for complexity change detection*/
ps_ctxt->i4_num_blks++;
if(ps_ed_ctb_l1_curr->i4_sad_cost_me_for_ref[z_scan_idx >> 2] >
(8 /*blk width*/ * 8 /*blk height*/ * (1 + ps_ctxt->num_b_frms)))
{
ps_ctxt->i4_num_blks_high_sad++;
}
}
}
}
/* EIID: Early inter intra decisions */
/* tap L1 level SAD for inter intra decisions */
if((e_me_quality_presets >= ME_MEDIUM_SPEED) &&
(!ps_ctxt->s_frm_prms
.is_i_pic)) //for high-quality preset->disable early decisions
{
if(1 == ps_refine_prms->i4_layer_id)
{
WORD32 i4_min_sad_cost_8x8_block = min_cost;
ihevce_ed_blk_t *ps_curr_ed_blk_ctxt;
WORD32 i4_diff_col_ctr = blk_x - (i4_ctb_blk_ctr * 4);
WORD32 i4_diff_row_ctr = blk_y - (i4_ctb_row_ctr * 4);
WORD32 z_scan_idx =
gau1_raster_scan_to_ctb[i4_diff_row_ctr][i4_diff_col_ctr];
ps_curr_ed_blk_ctxt = ps_ed_blk_ctxt_curr_ctb + z_scan_idx;
/*register the min cost for l1 me in blk context */
ps_ed_ctb_l1_curr->i4_best_sad_cost_8x8_l1_me[z_scan_idx >> 2] =
i4_min_sad_cost_8x8_block;
i4_num_comparisions++;
/* take early inter-intra decision here */
ps_curr_ed_blk_ctxt->intra_or_inter = 3; /*init saying eval both */
#if DISABLE_INTRA_IN_BPICS
if((e_me_quality_presets == ME_XTREME_SPEED_25) &&
(ps_ctxt->s_frm_prms.i4_temporal_layer_id > TEMPORAL_LAYER_DISABLE))
{
ps_curr_ed_blk_ctxt->intra_or_inter =
2; /*eval only inter if inter cost is less */
i4_num_inter_wins++;
}
else
#endif
{
if(ps_ed_ctb_l1_curr->i4_best_sad_cost_8x8_l1_me[z_scan_idx >> 2] <
((ps_ed_ctb_l1_curr->i4_best_sad_cost_8x8_l1_ipe[z_scan_idx >> 2] *
i4_threshold_multiplier) /
i4_threshold_divider))
{
ps_curr_ed_blk_ctxt->intra_or_inter =
2; /*eval only inter if inter cost is less */
i4_num_inter_wins++;
}
}
//{
// DBG_PRINTF ("(blk x, blk y):(%d, %d)\t me:(ctb_x, ctb_y):(%d, %d)\t intra_SAD_COST: %d\tInter_SAD_COST: %d\n",
// blk_x,blk_y,
// i4_ctb_blk_ctr, i4_ctb_row_ctr,
// ps_curr_ed_blk_ctxt->i4_best_sad_8x8_l1_ipe,
// i4_min_sad_cost_8x8_block
// );
//}
} //end of layer-1
} //end of if (e_me_quality_presets >= ME_MEDIUM_SPEED)
else
{
if(1 == ps_refine_prms->i4_layer_id)
{
WORD32 i4_min_sad_cost_8x8_block = min_cost;
WORD32 i4_diff_col_ctr = blk_x - (i4_ctb_blk_ctr * 4);
WORD32 i4_diff_row_ctr = blk_y - (i4_ctb_row_ctr * 4);
WORD32 z_scan_idx =
gau1_raster_scan_to_ctb[i4_diff_row_ctr][i4_diff_col_ctr];
/*register the min cost for l1 me in blk context */
ps_ed_ctb_l1_curr->i4_best_sad_cost_8x8_l1_me[z_scan_idx >> 2] =
i4_min_sad_cost_8x8_block;
}
}
if(1 == ps_refine_prms->i4_layer_id)
{
WORD32 i4_diff_col_ctr = blk_x - (i4_ctb_blk_ctr * 4);
WORD32 i4_diff_row_ctr = blk_y - (i4_ctb_row_ctr * 4);
WORD32 z_scan_idx =
gau1_raster_scan_to_ctb[i4_diff_row_ctr][i4_diff_col_ctr];
ps_ed_ctb_l1_curr->i4_best_sad_8x8_l1_me_for_decide[z_scan_idx >> 2] =
min_sad;
if(min_cost <
ps_ed_ctb_l1_curr->i4_best_sad_cost_8x8_l1_ipe[z_scan_idx >> 2])
{
ps_ctxt->i4_L1_hme_best_cost += min_cost;
ps_ctxt->i4_L1_hme_sad += min_sad;
ps_ed_ctb_l1_curr->i4_best_sad_8x8_l1_me[z_scan_idx >> 2] = min_sad;
}
else
{
ps_ctxt->i4_L1_hme_best_cost +=
ps_ed_ctb_l1_curr->i4_best_sad_cost_8x8_l1_ipe[z_scan_idx >> 2];
ps_ctxt->i4_L1_hme_sad +=
ps_ed_ctb_l1_curr->i4_best_sad_8x8_l1_ipe[z_scan_idx >> 2];
ps_ed_ctb_l1_curr->i4_best_sad_8x8_l1_me[z_scan_idx >> 2] =
ps_ed_ctb_l1_curr->i4_best_sad_8x8_l1_ipe[z_scan_idx >> 2];
}
}
}
}
/* Update the number of blocks processed in the current row */
if((ME_MEDIUM_SPEED > e_me_quality_presets))
{
ihevce_dmgr_set_row_row_sync(
pv_hme_dep_mngr,
(i4_ctb_x + 1),
blk_y,
0 /* Col Tile No. : Not supported in PreEnc*/);
}
}
/* set the output dependency after completion of row */
ihevce_pre_enc_grp_job_set_out_dep(ps_multi_thrd_ctxt, ps_job, i4_ping_pong);
}
}