/******************************************************************************
*
* 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_err_compute.c
*
* \brief
* SAD / SATD routines for error computation
*
* Detailed_description : Contains various types of SAD/SATD routines for
* error computation between a given input and reference ptr. The SAD
* routines can evaluate for either a single point or a grid, and can
* evaluate with either partial updates or no partial updates. Partial
* updates means evaluating sub block SADs, e.g. 4 4x4 subblock SAD in
* addition to the main 8x8 block SAD.
*
* \date
* 22/9/2012
*
* \author Ittiam
***************************************************************************
*/
/*****************************************************************************/
/* File Includes */
/*****************************************************************************/
/* System include files */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>
#include <math.h>
#include <limits.h>
/* User include files */
#include "ihevc_typedefs.h"
#include "itt_video_api.h"
#include "ihevce_api.h"
#include "rc_cntrl_param.h"
#include "rc_frame_info_collector.h"
#include "rc_look_ahead_params.h"
#include "ihevc_defs.h"
#include "ihevc_structs.h"
#include "ihevc_platform_macros.h"
#include "ihevc_deblk.h"
#include "ihevc_itrans_recon.h"
#include "ihevc_chroma_itrans_recon.h"
#include "ihevc_chroma_intra_pred.h"
#include "ihevc_intra_pred.h"
#include "ihevc_inter_pred.h"
#include "ihevc_mem_fns.h"
#include "ihevc_padding.h"
#include "ihevc_weighted_pred.h"
#include "ihevc_sao.h"
#include "ihevc_resi_trans.h"
#include "ihevc_quant_iquant_ssd.h"
#include "ihevc_cabac_tables.h"
#include "ihevce_defs.h"
#include "ihevce_lap_enc_structs.h"
#include "ihevce_multi_thrd_structs.h"
#include "ihevce_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_refine.h"
#include "hme_err_compute.h"
#include "hme_common_utils.h"
#include "hme_search_algo.h"
#include "ihevce_stasino_helpers.h"
/******************************************************************************
* MACRO DEFINITIONS
******************************************************************************/
/*****************************************************************************/
/* Theoritically, the various types of SAD functions that are needed for */
/* reasons of optimality. SADs that are to be evaluated at a single pt can be*/
/* more optimal than SADs that are to be evaluated for a grid of 3x3. The */
/* SADs to be evaluated at a grid are classified as separate functions, since*/
/* evaluating them on a single function call helps reuse inputs for a small */
/* grid of 3x3. Also, if no partial updates are required, there are 3 basic */
/* funcitons, width 4K (K = odd number), width 8K (K = odd number) and width */
/* 16K, K any number. For partial updates, it is assumed that the block size */
/* is square (8x8, 16x16, 32x32, 64x64) and further differentiation is done */
/* based on the basic evaluation unit. E.g. if 16x16 blk size requires, part */
/* update on AMP partitions, then basic SAD unit is 4x4, if it doesnt, then */
/* basic SAD unit is 8x8. */
/*****************************************************************************/
#define UPD_RES_PT_NPU_BEST1 hme_update_results_grid_pu_bestn
#define UPD_RES_PT_NPU_BESTN hme_update_results_grid_pu_bestn
#define UPD_RES_PT_PU_BEST1 hme_update_results_grid_pu_bestn
#define UPD_RES_PT_PU_BESTN hme_update_results_grid_pu_bestn
#define UPD_RES_GRID_NPU_BEST1 hme_update_results_grid_pu_bestn
#define UPD_RES_GRID_NPU_BESTN hme_update_results_grid_pu_bestn
#define UPD_RES_GRID_PU_BEST1 hme_update_results_grid_pu_bestn
#define UPD_RES_GRID_PU_BESTN hme_update_results_grid_pu_bestn
/*******************************************************************************
* FUNCTION DEFINITIONS
*******************************************************************************/
S32 hme_cmp_nodes(search_node_t *ps_best_node1, search_node_t *ps_best_node2)
{
if((ps_best_node1->s_mv.i2_mvx == ps_best_node2->s_mv.i2_mvx) &&
(ps_best_node1->s_mv.i2_mvy == ps_best_node2->s_mv.i2_mvy) &&
(ps_best_node1->i1_ref_idx == ps_best_node2->i1_ref_idx))
{
return 0;
}
return -1;
}
void compute_4x4_sads_for_16x16_blk(
grid_ctxt_t *ps_grid, /* Grid ctxt */
UWORD8 *pu1_cur_ptr, /* Pointer to top-left of current block */
WORD32 cur_buf_stride, /* Buffer stride of current buffer */
UWORD16 **
u2_part_sads, /* 2D Array containing SADs for all 17 partitions. As many rows as partitions. SADs in a row correspond to each of the candidates */
cand_t *ps_cand, /* Return the list of candidates evaluated */
WORD32 *num_cands /* Number of candidates that were processed */
)
{
WORD32 a, b, c, d, i;
WORD16 grd_sz_y = (ps_grid->grd_sz_y_x & 0xFFFF0000) >> 16;
WORD16 grd_sz_x = (ps_grid->grd_sz_y_x & 0xFFFF);
//WORD32 offset_x[9] = {-grd_sz_x, 0, grd_sz_x, -grd_sz_x, 0, grd_sz_x, grd_sz_x, 0, -grd_sz_x};
//WORD32 offset_y[9] = {-grd_sz_y, -grd_sz_y, -grd_sz_y, 0, 0, 0, grd_sz_y, grd_sz_y, grd_sz_y};
/* Assumes the following order: C, L, T, R, B, TL, TR, BL, BR */
WORD32 offset_x[9] = { 0, -grd_sz_x, 0, grd_sz_x, 0, -grd_sz_x, grd_sz_x, -grd_sz_x, grd_sz_x };
WORD32 offset_y[9] = { 0, 0, -grd_sz_y, 0, grd_sz_y, -grd_sz_y, -grd_sz_y, grd_sz_y, grd_sz_y };
WORD32 ref_buf_stride = ps_grid->ref_buf_stride;
WORD32 cur_buf_stride_ls2 = (cur_buf_stride << 2);
WORD32 ref_buf_stride_ls2 = (ref_buf_stride << 2);
cand_t *cand0 = ps_cand;
UWORD16 au2_4x4_sad[NUM_4X4];
*num_cands = 0;
/* Loop to fill up the cand_t array and to calculate num_cands */
for(i = 0; i < ps_grid->num_grids; i++)
{
WORD32 j;
WORD32 mask = ps_grid->pi4_grd_mask[i];
UWORD8 *pu1_ref_ptr_center = ps_grid->ppu1_ref_ptr[i];
WORD32 mv_x = ps_grid->p_mv[i].i2_mv_x;
WORD32 mv_y = (ps_grid->p_mv[i].i2_mv_y);
for(j = 0; j < NUM_CANDIDATES_IN_GRID; j++, mask >>= 1)
{
if(mask & 1)
{
*num_cands = *num_cands + 1;
cand0->grid_ix = i;
cand0->ref_idx = ps_grid->p_ref_idx[i];
cand0->pu1_ref_ptr =
pu1_ref_ptr_center + offset_x[j] + ref_buf_stride * offset_y[j];
cand0->mv.i2_mv_x = (S16)(mv_x) + offset_x[j];
cand0->mv.i2_mv_y = (S16)(mv_y) + offset_y[j];
cand0++;
}
}
}
/* Loop to compute the SAD's */
for(a = 0; a < *num_cands; a++)
{
cand_t *cand = ps_cand + a;
memset(&au2_4x4_sad[0], 0, NUM_4X4 * sizeof(UWORD16));
for(b = 0; b < NUM_4X4; b++)
{
WORD32 t1 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * cur_buf_stride_ls2;
WORD32 t2 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * ref_buf_stride_ls2;
for(c = 0; c < NUM_ROWS_IN_4X4; c++)
{
WORD32 z_cur = (cur_buf_stride)*c + t1;
WORD32 z_ref = (ref_buf_stride)*c + t2;
for(d = 0; d < NUM_PIXELS_IN_ROW; d++)
{
au2_4x4_sad[b] += (UWORD16)ABS(
(((S32)cand->pu1_ref_ptr[(z_ref + d)]) - ((S32)pu1_cur_ptr[(z_cur + d)])));
}
}
}
u2_part_sads[PART_ID_NxN_TL][a] =
(au2_4x4_sad[0] + au2_4x4_sad[1] + au2_4x4_sad[4] + au2_4x4_sad[5]);
u2_part_sads[PART_ID_NxN_TR][a] =
(au2_4x4_sad[2] + au2_4x4_sad[3] + au2_4x4_sad[6] + au2_4x4_sad[7]);
u2_part_sads[PART_ID_NxN_BL][a] =
(au2_4x4_sad[8] + au2_4x4_sad[9] + au2_4x4_sad[12] + au2_4x4_sad[13]);
u2_part_sads[PART_ID_NxN_BR][a] =
(au2_4x4_sad[10] + au2_4x4_sad[11] + au2_4x4_sad[14] + au2_4x4_sad[15]);
u2_part_sads[PART_ID_Nx2N_L][a] =
u2_part_sads[PART_ID_NxN_TL][a] + u2_part_sads[PART_ID_NxN_BL][a];
u2_part_sads[PART_ID_Nx2N_R][a] =
u2_part_sads[PART_ID_NxN_TR][a] + u2_part_sads[PART_ID_NxN_BR][a];
u2_part_sads[PART_ID_2NxN_T][a] =
u2_part_sads[PART_ID_NxN_TR][a] + u2_part_sads[PART_ID_NxN_TL][a];
u2_part_sads[PART_ID_2NxN_B][a] =
u2_part_sads[PART_ID_NxN_BR][a] + u2_part_sads[PART_ID_NxN_BL][a];
u2_part_sads[PART_ID_nLx2N_L][a] =
(au2_4x4_sad[8] + au2_4x4_sad[0] + au2_4x4_sad[12] + au2_4x4_sad[4]);
u2_part_sads[PART_ID_nRx2N_R][a] =
(au2_4x4_sad[3] + au2_4x4_sad[7] + au2_4x4_sad[15] + au2_4x4_sad[11]);
u2_part_sads[PART_ID_2NxnU_T][a] =
(au2_4x4_sad[1] + au2_4x4_sad[0] + au2_4x4_sad[2] + au2_4x4_sad[3]);
u2_part_sads[PART_ID_2NxnD_B][a] =
(au2_4x4_sad[15] + au2_4x4_sad[14] + au2_4x4_sad[12] + au2_4x4_sad[13]);
u2_part_sads[PART_ID_2Nx2N][a] =
u2_part_sads[PART_ID_2NxN_T][a] + u2_part_sads[PART_ID_2NxN_B][a];
u2_part_sads[PART_ID_2NxnU_B][a] =
u2_part_sads[PART_ID_2Nx2N][a] - u2_part_sads[PART_ID_2NxnU_T][a];
u2_part_sads[PART_ID_2NxnD_T][a] =
u2_part_sads[PART_ID_2Nx2N][a] - u2_part_sads[PART_ID_2NxnD_B][a];
u2_part_sads[PART_ID_nRx2N_L][a] =
u2_part_sads[PART_ID_2Nx2N][a] - u2_part_sads[PART_ID_nRx2N_R][a];
u2_part_sads[PART_ID_nLx2N_R][a] =
u2_part_sads[PART_ID_2Nx2N][a] - u2_part_sads[PART_ID_nLx2N_L][a];
}
}
/**
********************************************************************************
* @fn compute_part_sads_for_MxM_blk(grid_ctxt_t *ps_grid,
* UWORD8 *pu1_cur_ptr,
* WORD32 cur_buf_stride,
* WORD32 **pi4_part_sads,
* cand_t *ps_cand,
* WORD32 *num_cands
*
* @brief Computes partial SADs and updates partition results for an MxM blk
* and does so for several grids of points. This can be used for
* 32x32/64x64 blks with 17 partition updates
*
*
* @param[in] ps_grid : Pointer to grid ctxt that has multiple grid of max
* 9 pts per grid
*
* @param[in] pu1_cur_ptr : Top left of input buffer
*
* @param[in] pi4_part_sads : array of pointers, each entry pointing to
* results to be updated for a given partition
*
* @return The ps_search_results structure has the best result updated for
* the 2Nx2N partition alone.
********************************************************************************
*/
void compute_part_sads_for_MxM_blk(
grid_ctxt_t *ps_grid,
UWORD8 *pu1_cur_ptr,
WORD32 cur_buf_stride,
WORD32 **pp_part_sads,
cand_t *ps_cand,
WORD32 *num_cands,
CU_SIZE_T e_cu_size)
{
WORD32 a, b, c, d, i;
WORD16 grd_sz_y = (ps_grid->grd_sz_y_x & 0xFFFF0000) >> 16;
WORD16 grd_sz_x = (ps_grid->grd_sz_y_x & 0xFFFF);
/* Assumes the following order: C, L, T, R, B, TL, TR, BL, BR */
WORD32 offset_x[9] = { 0, -grd_sz_x, 0, grd_sz_x, 0, -grd_sz_x, grd_sz_x, -grd_sz_x, grd_sz_x };
WORD32 offset_y[9] = { 0, 0, -grd_sz_y, 0, grd_sz_y, -grd_sz_y, -grd_sz_y, grd_sz_y, grd_sz_y };
WORD32 shift = (WORD32)e_cu_size;
WORD32 ref_buf_stride = ps_grid->ref_buf_stride;
WORD32 cur_buf_stride_lsN = (cur_buf_stride << (1 + shift));
WORD32 ref_buf_stride_lsN = (ref_buf_stride << (1 + shift));
/* Num rows and pixels per row: 8 for CU_32x32 and 16 for CU_64x64 */
WORD32 num_rows_in_nxn = 2 << shift;
WORD32 num_pixels_in_row = 2 << shift;
cand_t *cand0 = ps_cand;
/* for a 2Nx2N partition we evaluate nxn SADs, where n = N/2. This is */
/* needed for AMP cases. */
WORD32 a_nxn_sad[NUM_4X4];
*num_cands = 0;
/* Loop to fill up the cand_t array and to calculate num_cands */
for(i = 0; i < ps_grid->num_grids; i++)
{
WORD32 j;
WORD32 mask = ps_grid->pi4_grd_mask[i];
UWORD8 *pu1_ref_ptr_center = ps_grid->ppu1_ref_ptr[i];
WORD32 mv_x = ps_grid->p_mv[i].i2_mv_x;
WORD32 mv_y = (ps_grid->p_mv[i].i2_mv_y);
for(j = 0; j < NUM_CANDIDATES_IN_GRID; j++, mask >>= 1)
{
if(mask & 1)
{
*num_cands = *num_cands + 1;
cand0->grid_ix = i;
cand0->ref_idx = ps_grid->p_ref_idx[i];
cand0->pu1_ref_ptr =
pu1_ref_ptr_center + offset_x[j] + ref_buf_stride * offset_y[j];
cand0->mv.i2_mv_x = (S16)(mv_x) + offset_x[j];
cand0->mv.i2_mv_y = (S16)(mv_y) + offset_y[j];
cand0++;
}
}
}
/* Loop to compute the SAD's */
for(a = 0; a < *num_cands; a++)
{
cand_t *cand = ps_cand + a;
memset(&a_nxn_sad[0], 0, NUM_4X4 * sizeof(WORD32));
for(b = 0; b < NUM_4X4; b++)
{
WORD32 t1 = (b % 4) * num_pixels_in_row + (b >> 2) * cur_buf_stride_lsN;
WORD32 t2 = (b % 4) * num_pixels_in_row + (b >> 2) * ref_buf_stride_lsN;
for(c = 0; c < num_rows_in_nxn; c++)
{
WORD32 z_cur = (cur_buf_stride)*c + t1;
WORD32 z_ref = (ref_buf_stride)*c + t2;
for(d = 0; d < num_pixels_in_row; d++)
{
a_nxn_sad[b] += (WORD32)ABS(
(((WORD32)cand->pu1_ref_ptr[(z_ref + d)]) -
((WORD32)pu1_cur_ptr[(z_cur + d)])));
}
}
}
pp_part_sads[PART_ID_NxN_TL][a] =
(a_nxn_sad[0] + a_nxn_sad[1] + a_nxn_sad[4] + a_nxn_sad[5]);
pp_part_sads[PART_ID_NxN_TR][a] =
(a_nxn_sad[2] + a_nxn_sad[3] + a_nxn_sad[6] + a_nxn_sad[7]);
pp_part_sads[PART_ID_NxN_BL][a] =
(a_nxn_sad[8] + a_nxn_sad[9] + a_nxn_sad[12] + a_nxn_sad[13]);
pp_part_sads[PART_ID_NxN_BR][a] =
(a_nxn_sad[10] + a_nxn_sad[11] + a_nxn_sad[14] + a_nxn_sad[15]);
pp_part_sads[PART_ID_Nx2N_L][a] =
pp_part_sads[PART_ID_NxN_TL][a] + pp_part_sads[PART_ID_NxN_BL][a];
pp_part_sads[PART_ID_Nx2N_R][a] =
pp_part_sads[PART_ID_NxN_TR][a] + pp_part_sads[PART_ID_NxN_BR][a];
pp_part_sads[PART_ID_2NxN_T][a] =
pp_part_sads[PART_ID_NxN_TR][a] + pp_part_sads[PART_ID_NxN_TL][a];
pp_part_sads[PART_ID_2NxN_B][a] =
pp_part_sads[PART_ID_NxN_BR][a] + pp_part_sads[PART_ID_NxN_BL][a];
pp_part_sads[PART_ID_nLx2N_L][a] =
(a_nxn_sad[8] + a_nxn_sad[0] + a_nxn_sad[12] + a_nxn_sad[4]);
pp_part_sads[PART_ID_nRx2N_R][a] =
(a_nxn_sad[3] + a_nxn_sad[7] + a_nxn_sad[15] + a_nxn_sad[11]);
pp_part_sads[PART_ID_2NxnU_T][a] =
(a_nxn_sad[1] + a_nxn_sad[0] + a_nxn_sad[2] + a_nxn_sad[3]);
pp_part_sads[PART_ID_2NxnD_B][a] =
(a_nxn_sad[15] + a_nxn_sad[14] + a_nxn_sad[12] + a_nxn_sad[13]);
pp_part_sads[PART_ID_2Nx2N][a] =
pp_part_sads[PART_ID_2NxN_T][a] + pp_part_sads[PART_ID_2NxN_B][a];
pp_part_sads[PART_ID_2NxnU_B][a] =
pp_part_sads[PART_ID_2Nx2N][a] - pp_part_sads[PART_ID_2NxnU_T][a];
pp_part_sads[PART_ID_2NxnD_T][a] =
pp_part_sads[PART_ID_2Nx2N][a] - pp_part_sads[PART_ID_2NxnD_B][a];
pp_part_sads[PART_ID_nRx2N_L][a] =
pp_part_sads[PART_ID_2Nx2N][a] - pp_part_sads[PART_ID_nRx2N_R][a];
pp_part_sads[PART_ID_nLx2N_R][a] =
pp_part_sads[PART_ID_2Nx2N][a] - pp_part_sads[PART_ID_nLx2N_L][a];
}
}
void hme_evalsad_grid_pu_16x16(err_prms_t *ps_prms)
{
grid_ctxt_t s_grid;
cand_t as_candt[9];
U16 au2_sad_grid[TOT_NUM_PARTS * 9];
U16 *apu2_sad_grid[TOT_NUM_PARTS];
hme_mv_t s_mv = { 0, 0 };
S32 i4_ref_idx = 0, i;
S32 num_candts = 0;
s_grid.num_grids = 1;
s_grid.ref_buf_stride = ps_prms->i4_ref_stride;
s_grid.grd_sz_y_x = ((ps_prms->i4_step << 16) | ps_prms->i4_step);
s_grid.ppu1_ref_ptr = &ps_prms->pu1_ref;
s_grid.pi4_grd_mask = &ps_prms->i4_grid_mask;
s_grid.p_mv = &s_mv;
s_grid.p_ref_idx = &i4_ref_idx;
for(i = 0; i < 9; i++)
{
if(s_grid.pi4_grd_mask[0] & (1 << i))
num_candts++;
}
for(i = 0; i < TOT_NUM_PARTS; i++)
apu2_sad_grid[i] = &au2_sad_grid[i * num_candts];
compute_4x4_sads_for_16x16_blk(
&s_grid, ps_prms->pu1_inp, ps_prms->i4_inp_stride, apu2_sad_grid, as_candt, &num_candts);
for(i = 0; i < TOT_NUM_PARTS * num_candts; i++)
{
ps_prms->pi4_sad_grid[i] = au2_sad_grid[i];
}
}
void hme_evalsad_grid_npu_MxN(err_prms_t *ps_prms)
{
U08 *pu1_inp_base, *pu1_ref_c;
S32 *pi4_sad = ps_prms->pi4_sad_grid;
S32 i, grid_count = 0;
S32 step = ps_prms->i4_step;
S32 x_off = step, y_off = step * ps_prms->i4_ref_stride;
ASSERT((ps_prms->i4_part_mask & (ps_prms->i4_part_mask - 1)) == 0);
//assert(ps_prms->i4_blk_ht <= 8);
//assert(ps_prms->i4_blk_wd <= 8);
for(i = 0; i < 9; i++)
{
if(ps_prms->i4_grid_mask & (1 << i))
grid_count++;
}
pi4_sad += (ps_prms->pi4_valid_part_ids[0] * grid_count);
pu1_inp_base = ps_prms->pu1_inp;
pu1_ref_c = ps_prms->pu1_ref;
for(i = 0; i < 9; i++)
{
S32 sad = 0, j, k;
U08 *pu1_inp, *pu1_ref;
if(!(ps_prms->i4_grid_mask & (1 << i)))
continue;
pu1_ref = pu1_ref_c + x_off * gai1_grid_id_to_x[i];
pu1_ref += y_off * gai1_grid_id_to_y[i];
pu1_inp = pu1_inp_base;
for(j = 0; j < ps_prms->i4_blk_ht; j++)
{
for(k = 0; k < ps_prms->i4_blk_wd; k++)
{
sad += (ABS((pu1_inp[k] - pu1_ref[k])));
}
pu1_inp += ps_prms->i4_inp_stride;
pu1_ref += ps_prms->i4_ref_stride;
}
*pi4_sad++ = sad;
}
}
WORD32 hme_evalsad_pt_npu_MxN_8bit_compute(
WORD32 ht,
WORD32 wd,
UWORD8 *pu1_inp,
UWORD8 *pu1_ref,
WORD32 i4_inp_stride,
WORD32 i4_ref_stride)
{
WORD32 i, j;
WORD32 sad = 0;
for(i = 0; i < ht; i++)
{
for(j = 0; j < wd; j++)
{
sad += (ABS(((S32)pu1_inp[j] - (S32)pu1_ref[j])));
}
pu1_inp += i4_inp_stride;
pu1_ref += i4_ref_stride;
}
return sad;
}
void hme_evalsad_pt_npu_MxN_8bit(err_prms_t *ps_prms)
{
S32 wd, ht;
U08 *pu1_inp, *pu1_ref;
wd = ps_prms->i4_blk_wd;
ht = ps_prms->i4_blk_ht;
pu1_inp = ps_prms->pu1_inp;
pu1_ref = ps_prms->pu1_ref;
ps_prms->pi4_sad_grid[0] = hme_evalsad_pt_npu_MxN_8bit_compute(
ht, wd, pu1_inp, pu1_ref, ps_prms->i4_inp_stride, ps_prms->i4_ref_stride);
}
void compute_satd_8bit(err_prms_t *ps_prms)
{
U08 *pu1_origin;
S32 src_strd;
U08 *pu1_pred_buf;
S32 dst_strd;
S32 wd, ht;
U32 u4_sad = 0;
WORD32 x, y;
U08 *u1_pi0, *u1_pi1;
pu1_origin = ps_prms->pu1_inp;
pu1_pred_buf = ps_prms->pu1_ref;
src_strd = ps_prms->i4_inp_stride;
dst_strd = ps_prms->i4_ref_stride;
wd = ps_prms->i4_blk_wd;
ht = ps_prms->i4_blk_ht;
u1_pi0 = pu1_origin;
u1_pi1 = pu1_pred_buf;
/* Follows the following logic:
For block sizes less than or equal to 16X16, the basic transform size is 4x4
For block sizes greater than or equal to 32x32, the basic transform size is 8x8 */
if((wd > 0x10) || (ht > 0x10))
{
for(y = 0; y < ht; y += 8)
{
for(x = 0; x < wd; x += 8)
{
u4_sad += ps_prms->ps_cmn_utils_optimised_function_list->pf_HAD_8x8_8bit(
&u1_pi0[x], src_strd, &u1_pi1[x], dst_strd, NULL, 1);
}
u1_pi0 += src_strd * 8;
u1_pi1 += dst_strd * 8;
}
}
else
{
for(y = 0; y < ht; y += 4)
{
for(x = 0; x < wd; x += 4)
{
u4_sad += ps_prms->ps_cmn_utils_optimised_function_list->pf_HAD_4x4_8bit(
&u1_pi0[x], src_strd, &u1_pi1[x], dst_strd, NULL, 1);
}
u1_pi0 += src_strd * 4;
u1_pi1 += dst_strd * 4;
}
}
ps_prms->pi4_sad_grid[0] = (S32)u4_sad;
}
void hme_init_pred_part(
pred_ctxt_t *ps_pred_ctxt,
search_node_t *ps_tl,
search_node_t *ps_t,
search_node_t *ps_tr,
search_node_t *ps_l,
search_node_t *ps_bl,
search_node_t *ps_coloc,
search_node_t *ps_zeromv,
search_node_t **pps_proj_coloc,
PART_ID_T e_part_id)
{
pred_candt_nodes_t *ps_candt_nodes;
ps_candt_nodes = &ps_pred_ctxt->as_pred_nodes[e_part_id];
ps_candt_nodes->ps_tl = ps_tl;
ps_candt_nodes->ps_tr = ps_tr;
ps_candt_nodes->ps_t = ps_t;
ps_candt_nodes->ps_l = ps_l;
ps_candt_nodes->ps_bl = ps_bl;
ps_candt_nodes->ps_coloc = ps_coloc;
ps_candt_nodes->ps_zeromv = ps_zeromv;
ps_candt_nodes->pps_proj_coloc = pps_proj_coloc;
}
void hme_init_pred_ctxt_no_encode(
pred_ctxt_t *ps_pred_ctxt,
search_results_t *ps_search_results,
search_node_t *ps_top_candts,
search_node_t *ps_left_candts,
search_node_t **pps_proj_coloc_candts,
search_node_t *ps_coloc_candts,
search_node_t *ps_zeromv_candt,
S32 pred_lx,
S32 lambda,
S32 lambda_q_shift,
U08 **ppu1_ref_bits_tlu,
S16 *pi2_ref_scf)
{
search_node_t *ps_invalid, *ps_l, *ps_t, *ps_tl, *ps_tr, *ps_bl;
search_node_t *ps_coloc;
PART_ID_T e_part_id;
/* Assume that resolution is subpel to begin with */
ps_pred_ctxt->mv_pel = 0; // FPEL
/* lambda and pred_lx (PRED_L0/PRED_L1) */
ps_pred_ctxt->lambda = lambda;
ps_pred_ctxt->lambda_q_shift = lambda_q_shift;
ps_pred_ctxt->pred_lx = pred_lx;
ps_pred_ctxt->ppu1_ref_bits_tlu = ppu1_ref_bits_tlu;
ps_pred_ctxt->pi2_ref_scf = pi2_ref_scf;
ps_pred_ctxt->proj_used = 0;
/* Bottom left should not be valid */
ASSERT(ps_left_candts[2].u1_is_avail == 0);
ps_invalid = &ps_left_candts[2];
/*************************************************************************/
/* for the case of no encode, the idea is to set up cants as follows */
/* */
/* ____ ______________ */
/* | TL | T | T1 | TR | */
/* |____|____|____|____| */
/* | L | b0 | b1 | */
/* |____|____|____| */
/* | L1 | b2 | b3 | */
/* |____|____|____| */
/* | BL | */
/* |____| */
/* */
/* If use_4x4 is 0, then b0,b1,b2,b3 are single 8x8 blk. then T=T1 */
/* and L=L1. topleft, top and topright are TL,T,TR respectively */
/* Left and bottom left is L and BL respectively. */
/* If use_4x4 is 1: then the above holds true only for PARTID = 0 (8x8) */
/* For the 4 subblocks (partids 4-7) */
/* */
/* Block Left Top Top Left Top Right Bottom Left */
/* b0 L T TL T1 L1 */
/* b1 b0 T1 T TR BL(invalid) */
/* b2 L1 b0 L0 b1 BL (invalid) */
/* b3 b2 b1 b0 BL(inv) BL (inv) */
/* */
/* Note : For block b1, bottom left pts to b2, which is not yet ready */
/* hence it is kept invalid and made to pt to BL. For block b3 top rt */
/* is invalid and hence made to pt to BL which is invalid. */
/* BL is invalid since it lies in a bottom left 8x8 blk and not yet ready*/
/*************************************************************************/
/* ps_coloc always points to a fixe candt (global) */
/* TODO : replace incoming ps_coloc from global to geniune coloc */
ps_coloc = ps_coloc_candts;
/* INITIALIZATION OF 8x8 BLK */
ps_tl = ps_top_candts;
ps_t = ps_tl + 2;
ps_tr = ps_t + 1;
ps_l = ps_left_candts + 1;
ps_bl = ps_invalid;
e_part_id = PART_ID_2Nx2N;
hme_init_pred_part(
ps_pred_ctxt,
ps_tl,
ps_t,
ps_tr,
ps_l,
ps_bl,
ps_coloc,
ps_zeromv_candt,
pps_proj_coloc_candts,
e_part_id);
/* INITIALIZATION OF 4x4 TL BLK */
e_part_id = PART_ID_NxN_TL;
ps_tl = ps_top_candts;
ps_t = ps_tl + 1;
ps_tr = ps_t + 1;
ps_l = ps_left_candts;
ps_bl = ps_l + 1;
hme_init_pred_part(
ps_pred_ctxt,
ps_tl,
ps_t,
ps_tr,
ps_l,
ps_bl,
ps_coloc,
ps_zeromv_candt,
pps_proj_coloc_candts,
e_part_id);
/* INITIALIZATION OF 4x4 TR BLK */
e_part_id = PART_ID_NxN_TR;
ps_tl = ps_top_candts + 1;
ps_t = ps_tl + 1;
ps_tr = ps_t + 1;
ps_l = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_TL];
ps_bl = ps_invalid;
hme_init_pred_part(
ps_pred_ctxt,
ps_tl,
ps_t,
ps_tr,
ps_l,
ps_bl,
ps_coloc,
ps_zeromv_candt,
pps_proj_coloc_candts,
e_part_id);
/* INITIALIZATION OF 4x4 BL BLK */
e_part_id = PART_ID_NxN_BL;
ps_tl = ps_left_candts;
ps_t = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_TL];
ps_tr = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_TR];
ps_l = ps_left_candts + 1;
ps_bl = ps_invalid; //invalid
hme_init_pred_part(
ps_pred_ctxt,
ps_tl,
ps_t,
ps_tr,
ps_l,
ps_bl,
ps_coloc,
ps_zeromv_candt,
pps_proj_coloc_candts,
e_part_id);
/* INITIALIZATION OF 4x4 BR BLK */
e_part_id = PART_ID_NxN_BR;
ps_tl = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_TL];
ps_t = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_TR];
ps_tr = ps_invalid; // invalid
ps_l = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_BL];
ps_bl = ps_invalid; // invalid
hme_init_pred_part(
ps_pred_ctxt,
ps_tl,
ps_t,
ps_tr,
ps_l,
ps_bl,
ps_coloc,
ps_zeromv_candt,
pps_proj_coloc_candts,
e_part_id);
}
void hme_init_pred_ctxt_encode(
pred_ctxt_t *ps_pred_ctxt,
search_results_t *ps_search_results,
search_node_t *ps_coloc_candts,
search_node_t *ps_zeromv_candt,
mv_grid_t *ps_mv_grid,
S32 pred_lx,
S32 lambda,
S32 lambda_q_shift,
U08 **ppu1_ref_bits_tlu,
S16 *pi2_ref_scf)
{
search_node_t *ps_invalid, *ps_l, *ps_t, *ps_tl, *ps_tr, *ps_bl;
search_node_t *ps_coloc;
search_node_t *ps_grid_cu_base;
CU_SIZE_T e_cu_size = ps_search_results->e_cu_size;
/* Part Start, Part sizes in 4x4 units */
S32 part_wd, part_ht, part_start_x, part_start_y;
/* Partition type, number of partitions in type */
S32 part_id;
/* Coordinates of the CU in 4x4 units */
S32 cu_start_x, cu_start_y;
S32 shift = e_cu_size;
/* top right and bot left validity at CU level */
S32 cu_tr_valid, cu_bl_valid;
/* strideo f the grid */
S32 grid_stride = ps_mv_grid->i4_stride;
ps_pred_ctxt->lambda = lambda;
ps_pred_ctxt->lambda_q_shift = lambda_q_shift;
ps_pred_ctxt->pred_lx = pred_lx;
ps_pred_ctxt->mv_pel = 0;
ps_pred_ctxt->ppu1_ref_bits_tlu = ppu1_ref_bits_tlu;
ps_pred_ctxt->pi2_ref_scf = pi2_ref_scf;
ps_pred_ctxt->proj_used = 1;
cu_start_x = ps_search_results->u1_x_off >> 2;
cu_start_y = ps_search_results->u1_y_off >> 2;
/* Coloc always points to fixed global candt */
ps_coloc = ps_coloc_candts;
/* Go to base of the CU in the MV Grid */
ps_grid_cu_base = &ps_mv_grid->as_node[0];
ps_grid_cu_base += (ps_mv_grid->i4_start_offset + cu_start_x);
ps_grid_cu_base += (grid_stride * cu_start_y);
/* points to the real bottom left of the grid, will never be valid */
ps_invalid = &ps_mv_grid->as_node[0];
ps_invalid += (grid_stride * 17);
{
S32 shift = 1 + e_cu_size;
cu_tr_valid = gau1_cu_tr_valid[cu_start_y >> shift][cu_start_x >> shift];
cu_bl_valid = gau1_cu_bl_valid[cu_start_y >> shift][cu_start_x >> shift];
}
/*************************************************************************/
/* for the case of encode, the idea is to set up cants as follows */
/* */
/* ____ ______________ ____ ____ */
/* | T0 | T1 | T2 | T3 | T4 | T5 | */
/* |____|____|____|____|____|____| */
/* | L1 | | | */
/* |____| | | */
/* | L2 | p0 | p1 | */
/* |____| | | */
/* | L3 | | | */
/* |____| | | */
/* | L4 | L' | | */
/* |____|____|______________| */
/* | BL | */
/* |____| */
/* The example is shown with 16x16 CU, though it can be generalized */
/* This CU has 2 partitions, cu_wd = 4. also p_wd, p_ht are partition */
/* width and ht in 4x4 units. */
/* For a given CU, derive the top left, top and bottom left and top rt */
/* pts. Left and top are assumed to be valid. */
/* IF there aretwo partitions in the CU (like p0 and p1) and vertical, */
/* then for first partition, left, top, top left and top right valid */
/* Bottom left is valid. store these validity flags. Also store the */
/* grid offsets of the partitions w.r.t. CU start in units of 4x4.For p0*/
/* Left grid offset = -1, 3. Top Grd offset = -1, 0. */
/* Top left grid offset = -1, -1. Top right = 1, -1. BL = -1, 4. */
/* For p1, validity flags are left, top, top left, top right, valid. */
/* BL is invalid. Grid offsets are: Left = dont care. T = 1, -1 (T2) */
/* TR = 4, -1 (T5). TL = 0, -1 (T1). BL = don't care. */
/* For p1, set the left pred candt to the best search result of p0. */
/*************************************************************************/
/* Loop over all partitions, and identify the 5 neighbours */
for(part_id = 0; part_id < TOT_NUM_PARTS; part_id++)
{
part_attr_t *ps_part_attr = &gas_part_attr_in_cu[part_id];
S32 tr_valid, bl_valid, is_vert;
search_node_t *ps_grid_pu_base;
PART_TYPE_T e_part_type;
PART_ID_T first_part;
S32 part_num;
e_part_type = ge_part_id_to_part_type[part_id];
first_part = ge_part_type_to_part_id[e_part_type][0];
is_vert = gau1_is_vert_part[e_part_type];
part_num = gau1_part_id_to_part_num[part_id];
tr_valid = gau1_partid_tr_valid[part_id] & cu_tr_valid;
bl_valid = gau1_partid_bl_valid[part_id] & cu_bl_valid;
part_start_x = (ps_part_attr->u1_x_start << shift) >> 2;
part_start_y = (ps_part_attr->u1_y_start << shift) >> 2;
part_wd = (ps_part_attr->u1_x_count << shift) >> 2;
part_ht = (ps_part_attr->u1_y_count << shift) >> 2;
/* go to top left of part */
ps_grid_pu_base = ps_grid_cu_base + part_start_x;
ps_grid_pu_base += (part_start_y * grid_stride);
ps_tl = ps_grid_pu_base - 1 - grid_stride;
ps_t = ps_grid_pu_base - grid_stride + part_wd - 1;
ps_l = ps_grid_pu_base - 1 + ((part_ht - 1) * grid_stride);
ps_tr = ps_t + 1;
ps_bl = ps_l + grid_stride;
if(!tr_valid)
ps_tr = ps_invalid;
if(!bl_valid)
ps_bl = ps_invalid;
if(part_num == 1)
{
/* for cases of two partitions 2nd part has 1st part as candt */
/* if vertical type, left candt of 2nd part is 1st part. */
/* if horz type, top candt of 2nd part is 1st part. */
if(is_vert)
{
ps_l = ps_search_results->aps_part_results[pred_lx][first_part];
}
else
{
ps_t = ps_search_results->aps_part_results[pred_lx][first_part];
}
}
if(part_num == 2)
{
/* only possible for NxN_BL */
ps_t = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_TL];
ps_tr = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_TR];
}
if(part_num == 3)
{
/* only possible for NxN_BR */
ps_t = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_TR];
ps_tl = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_TL];
ps_l = ps_search_results->aps_part_results[pred_lx][PART_ID_NxN_BL];
}
hme_init_pred_part(
ps_pred_ctxt,
ps_tl,
ps_t,
ps_tr,
ps_l,
ps_bl,
ps_coloc,
ps_zeromv_candt,
NULL,
(PART_ID_T)part_id);
}
}
/**
********************************************************************************
* @fn compute_mv_cost_explicit(search_node_t *ps_node,
* pred_ctxt_t *ps_pred_ctxt,
* PART_ID_T e_part_id)
*
* @brief MV cost for explicit search in layers not encoded
*
* @param[in] ps_node: search node having mv and ref id for which to eval cost
*
* @param[in] ps_pred_ctxt : mv pred context
*
* @param[in] e_part_id : Partition id.
*
* @return Cost value
********************************************************************************
*/
S32 compute_mv_cost_explicit(
search_node_t *ps_node, pred_ctxt_t *ps_pred_ctxt, PART_ID_T e_part_id, S32 inp_mv_pel)
{
#define RETURN_FIXED_COST 0
search_node_t *ps_pred_node_a = NULL, *ps_pred_node_b = NULL;
pred_candt_nodes_t *ps_pred_nodes;
S32 inp_shift = 2 - inp_mv_pel;
S32 pred_shift = 2 - ps_pred_ctxt->mv_pel;
S32 mv_p_x, mv_p_y;
S16 mvdx1, mvdx2, mvdy1, mvdy2;
S32 cost, ref_bits;
/*************************************************************************/
/* Logic for cost computation for explicit search. For such a search, */
/* it is guaranteed that all predictor candts have same ref id. The only */
/* probable issue is with the availability which needs checking. This fxn*/
/* does not suffer the need to scale predictor candts due to diff ref id */
/*************************************************************************/
/* Hack: currently we always assume 2Nx2N. */
/* TODO: get rid of this hack and return cost tuned to each partition */
ps_pred_nodes = &ps_pred_ctxt->as_pred_nodes[e_part_id];
ref_bits = ps_pred_ctxt->ppu1_ref_bits_tlu[ps_pred_ctxt->pred_lx][ps_node->i1_ref_idx];
/*************************************************************************/
/* Priority to bottom left availability. Else we go to left. If both are */
/* not available, then a remains null */
/*************************************************************************/
if(ps_pred_nodes->ps_tl->u1_is_avail)
ps_pred_node_a = ps_pred_nodes->ps_tl;
else if(ps_pred_nodes->ps_l->u1_is_avail)
ps_pred_node_a = ps_pred_nodes->ps_l;
/*************************************************************************/
/* For encoder, top left may not be really needed unless we use slices, */
/* and even then in ME it may not be relevant. So we only consider T or */
/* TR, as, if both T and TR are not available, TL also will not be */
/*************************************************************************/
if(ps_pred_nodes->ps_tr->u1_is_avail)
ps_pred_node_b = ps_pred_nodes->ps_tr;
else if(ps_pred_nodes->ps_t->u1_is_avail)
ps_pred_node_b = ps_pred_nodes->ps_t;
if(ps_pred_node_a == NULL)
{
ps_pred_node_a = ps_pred_nodes->ps_coloc;
if(ps_pred_node_b == NULL)
ps_pred_node_b = ps_pred_nodes->ps_zeromv;
}
else if(ps_pred_node_b == NULL)
ps_pred_node_b = ps_pred_nodes->ps_coloc;
else if(0 == hme_cmp_nodes(ps_pred_node_a, ps_pred_node_b))
{
ps_pred_node_b = ps_pred_nodes->ps_coloc;
}
mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
COMPUTE_DIFF_MV(mvdx1, mvdy1, ps_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
mv_p_x = ps_pred_node_b->s_mv.i2_mvx;
mv_p_y = ps_pred_node_b->s_mv.i2_mvy;
COMPUTE_DIFF_MV(mvdx2, mvdy2, ps_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx2 = ABS(mvdx2);
mvdy2 = ABS(mvdy2);
if((mvdx1 + mvdy1) < (mvdx2 + mvdy2))
{
cost =
hme_get_range(mvdx1) + hme_get_range(mvdy1) + (mvdx1 > 0) + (mvdy1 > 0) + ref_bits + 2;
}
else
{
cost =
hme_get_range(mvdx2) + hme_get_range(mvdy2) + (mvdx2 > 0) + (mvdy2 > 0) + ref_bits + 2;
}
{
S32 rnd = 1 << (ps_pred_ctxt->lambda_q_shift - 1);
return ((cost * ps_pred_ctxt->lambda + rnd) >> ps_pred_ctxt->lambda_q_shift);
}
}
/**
********************************************************************************
* @fn compute_mv_cost_coarse(search_node_t *ps_node,
* pred_ctxt_t *ps_pred_ctxt,
* PART_ID_T e_part_id)
*
* @brief MV cost for coarse explicit search in coarsest layer
*
* @param[in] ps_node: search node having mv and ref id for which to eval cost
*
* @param[in] ps_pred_ctxt : mv pred context
*
* @param[in] e_part_id : Partition id.
*
* @return Cost value
********************************************************************************
*/
S32 compute_mv_cost_coarse(
search_node_t *ps_node, pred_ctxt_t *ps_pred_ctxt, PART_ID_T e_part_id, S32 inp_mv_pel)
{
ARG_NOT_USED(e_part_id);
return (compute_mv_cost_explicit(ps_node, ps_pred_ctxt, PART_ID_2Nx2N, inp_mv_pel));
}
/**
********************************************************************************
* @fn compute_mv_cost_coarse_high_speed(search_node_t *ps_node,
* pred_ctxt_t *ps_pred_ctxt,
* PART_ID_T e_part_id)
*
* @brief MV cost for coarse explicit search in coarsest layer
*
* @param[in] ps_node: search node having mv and ref id for which to eval cost
*
* @param[in] ps_pred_ctxt : mv pred context
*
* @param[in] e_part_id : Partition id.
*
* @return Cost value
********************************************************************************
*/
S32 compute_mv_cost_coarse_high_speed(
search_node_t *ps_node, pred_ctxt_t *ps_pred_ctxt, PART_ID_T e_part_id, S32 inp_mv_pel)
{
S32 rnd, mvx, mvy, i4_search_idx;
S32 cost;
mvx = ps_node->s_mv.i2_mvx;
mvy = ps_node->s_mv.i2_mvy;
i4_search_idx = ps_node->i1_ref_idx;
cost = (2 * hme_get_range(ABS(mvx)) - 1) + (2 * hme_get_range(ABS(mvy)) - 1) + i4_search_idx;
cost += (mvx != 0) ? 1 : 0;
cost += (mvy != 0) ? 1 : 0;
rnd = 1 << (ps_pred_ctxt->lambda_q_shift - 1);
cost = (cost * ps_pred_ctxt->lambda + rnd) >> ps_pred_ctxt->lambda_q_shift;
return cost;
}
/**
********************************************************************************
* @fn compute_mv_cost_explicit_refine(search_node_t *ps_node,
* pred_ctxt_t *ps_pred_ctxt,
* PART_ID_T e_part_id)
*
* @brief MV cost for explicit search in layers not encoded. Always returns
* cost of the projected colocated candidate
*
* @param[in] ps_node: search node having mv and ref id for which to eval cost
*
* @param[in] ps_pred_ctxt : mv pred context
*
* @param[in] e_part_id : Partition id.
*
* @return Cost value
********************************************************************************
*/
S32 compute_mv_cost_explicit_refine(
search_node_t *ps_node, pred_ctxt_t *ps_pred_ctxt, PART_ID_T e_part_id, S32 inp_mv_pel)
{
search_node_t *ps_pred_node_a = NULL;
pred_candt_nodes_t *ps_pred_nodes;
S32 inp_shift = 2 - inp_mv_pel;
S32 pred_shift = 2 - ps_pred_ctxt->mv_pel;
S32 mv_p_x, mv_p_y;
S16 mvdx1, mvdy1;
S32 cost, ref_bits;
ps_pred_nodes = &ps_pred_ctxt->as_pred_nodes[e_part_id];
ref_bits = ps_pred_ctxt->ppu1_ref_bits_tlu[ps_pred_ctxt->pred_lx][ps_node->i1_ref_idx];
ps_pred_node_a = ps_pred_nodes->pps_proj_coloc[0];
mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
COMPUTE_DIFF_MV(mvdx1, mvdy1, ps_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
cost = hme_get_range(mvdx1) + hme_get_range(mvdy1) + (mvdx1 > 0) + (mvdy1 > 0) + ref_bits + 2;
{
S32 rnd = 1 << (ps_pred_ctxt->lambda_q_shift - 1);
return ((cost * ps_pred_ctxt->lambda + rnd) >> ps_pred_ctxt->lambda_q_shift);
}
}
/**
********************************************************************************
* @fn compute_mv_cost_refine(search_node_t *ps_node,
* pred_ctxt_t *ps_pred_ctxt,
* PART_ID_T e_part_id)
*
* @brief MV cost for coarse explicit search in coarsest layer
*
* @param[in] ps_node: search node having mv and ref id for which to eval cost
*
* @param[in] ps_pred_ctxt : mv pred context
*
* @param[in] e_part_id : Partition id.
*
* @return Cost value
********************************************************************************
*/
S32 compute_mv_cost_refine(
search_node_t *ps_node, pred_ctxt_t *ps_pred_ctxt, PART_ID_T e_part_id, S32 inp_mv_pel)
{
return (compute_mv_cost_explicit_refine(ps_node, ps_pred_ctxt, e_part_id, inp_mv_pel));
}
S32 compute_mv_cost_implicit(
search_node_t *ps_node, pred_ctxt_t *ps_pred_ctxt, PART_ID_T e_part_id, S32 inp_mv_pel)
{
search_node_t *ps_pred_node_a = NULL, *ps_pred_node_b = NULL;
pred_candt_nodes_t *ps_pred_nodes;
S08 i1_ref_idx;
S08 i1_ref_tl = -1, i1_ref_tr = -1, i1_ref_t = -1;
S08 i1_ref_bl = -1, i1_ref_l = -1;
S32 inp_shift = 2 - inp_mv_pel;
S32 pred_shift; /* = 2 - ps_pred_ctxt->mv_pel;*/
S32 ref_bits, cost;
S32 mv_p_x, mv_p_y;
S16 mvdx1, mvdx2, mvdy1, mvdy2;
//return 0;
i1_ref_idx = ps_node->i1_ref_idx;
/*************************************************************************/
/* Logic for cost computation for explicit search. For such a search, */
/* it is guaranteed that all predictor candts have same ref id. The only */
/* probable issue is with the availability which needs checking. This fxn*/
/* does not suffer the need to scale predictor candts due to diff ref id */
/*************************************************************************/
ps_pred_nodes = &ps_pred_ctxt->as_pred_nodes[e_part_id];
ref_bits = ps_pred_ctxt->ppu1_ref_bits_tlu[ps_pred_ctxt->pred_lx][i1_ref_idx];
/*************************************************************************/
/* Priority to bottom left availability. Else we go to left. If both are */
/* not available, then a remains null */
/*************************************************************************/
if(ps_pred_nodes->ps_bl->u1_is_avail)
i1_ref_bl = ps_pred_nodes->ps_bl->i1_ref_idx;
if(ps_pred_nodes->ps_l->u1_is_avail)
i1_ref_l = ps_pred_nodes->ps_l->i1_ref_idx;
if(i1_ref_bl == i1_ref_idx)
ps_pred_node_a = ps_pred_nodes->ps_bl;
else if(i1_ref_l == i1_ref_idx)
ps_pred_node_a = ps_pred_nodes->ps_l;
if(ps_pred_node_a == NULL)
{
if(i1_ref_bl != -1)
ps_pred_node_a = ps_pred_nodes->ps_bl;
else if(i1_ref_l != -1)
ps_pred_node_a = ps_pred_nodes->ps_l;
}
/*************************************************************************/
/* For encoder, top left may not be really needed unless we use slices, */
/* and even then in ME it may not be relevant. So we only consider T or */
/* TR, as, if both T and TR are not available, TL also will not be */
/*************************************************************************/
if(ps_pred_nodes->ps_tr->u1_is_avail)
i1_ref_tr = ps_pred_nodes->ps_tr->i1_ref_idx;
if(ps_pred_nodes->ps_t->u1_is_avail)
i1_ref_t = ps_pred_nodes->ps_t->i1_ref_idx;
if(ps_pred_nodes->ps_tl->u1_is_avail)
i1_ref_tl = ps_pred_nodes->ps_tl->i1_ref_idx;
if(i1_ref_tr == i1_ref_idx)
ps_pred_node_b = ps_pred_nodes->ps_tr;
else if(i1_ref_t == i1_ref_idx)
ps_pred_node_b = ps_pred_nodes->ps_t;
else if(i1_ref_tl == i1_ref_idx)
ps_pred_node_b = ps_pred_nodes->ps_tl;
if(ps_pred_node_b == NULL)
{
if(i1_ref_tr != -1)
ps_pred_node_b = ps_pred_nodes->ps_tr;
else if(i1_ref_t != -1)
ps_pred_node_b = ps_pred_nodes->ps_t;
else if(i1_ref_tl != -1)
ps_pred_node_b = ps_pred_nodes->ps_tl;
}
if(ps_pred_node_a == NULL)
{
ps_pred_node_a = ps_pred_nodes->ps_coloc;
if(ps_pred_node_b == NULL)
ps_pred_node_b = ps_pred_nodes->ps_zeromv;
}
else if(ps_pred_node_b == NULL)
ps_pred_node_b = ps_pred_nodes->ps_coloc;
else if(0 == hme_cmp_nodes(ps_pred_node_a, ps_pred_node_b))
{
ps_pred_node_b = ps_pred_nodes->ps_coloc;
}
if(ps_pred_node_a->i1_ref_idx != i1_ref_idx)
{
SCALE_FOR_POC_DELTA(mv_p_x, mv_p_y, ps_pred_node_a, i1_ref_idx, ps_pred_ctxt->pi2_ref_scf);
}
else
{
mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
}
pred_shift = ps_pred_node_a->u1_subpel_done ? 0 : 2;
COMPUTE_DIFF_MV(mvdx1, mvdy1, ps_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
if(ps_pred_node_b->i1_ref_idx != i1_ref_idx)
{
SCALE_FOR_POC_DELTA(mv_p_x, mv_p_y, ps_pred_node_b, i1_ref_idx, ps_pred_ctxt->pi2_ref_scf);
}
else
{
mv_p_x = ps_pred_node_b->s_mv.i2_mvx;
mv_p_y = ps_pred_node_b->s_mv.i2_mvy;
}
pred_shift = ps_pred_node_b->u1_subpel_done ? 0 : 2;
COMPUTE_DIFF_MV(mvdx2, mvdy2, ps_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx2 = ABS(mvdx2);
mvdy2 = ABS(mvdy2);
if((mvdx1 + mvdy1) < (mvdx2 + mvdy2))
{
cost = 2 * hme_get_range(mvdx1) + 2 * hme_get_range(mvdy1) + 2 * (mvdx1 > 0) +
2 * (mvdy1 > 0) + ref_bits + 2;
}
else
{
cost = 2 * hme_get_range(mvdx2) + 2 * hme_get_range(mvdy2) + 2 * (mvdx2 > 0) +
2 * (mvdy2 > 0) + ref_bits + 2;
}
{
/* Part bits in Q1, so evaluate cost as ((mv_cost<<1) + partbitsQ1 + rnd)>>(q+1)*/
S32 rnd = 1 << (ps_pred_ctxt->lambda_q_shift);
S32 tot_cost = (cost * ps_pred_ctxt->lambda) << 1;
tot_cost += (gau1_bits_for_part_id_q1[e_part_id] * ps_pred_ctxt->lambda);
return ((tot_cost + rnd) >> (ps_pred_ctxt->lambda_q_shift + 1));
}
}
S32 compute_mv_cost_implicit_high_speed(
search_node_t *ps_node, pred_ctxt_t *ps_pred_ctxt, PART_ID_T e_part_id, S32 inp_mv_pel)
{
search_node_t *ps_pred_node_a = NULL, *ps_pred_node_b = NULL;
pred_candt_nodes_t *ps_pred_nodes;
S08 i1_ref_idx;
S08 i1_ref_tr = -1;
S08 i1_ref_l = -1;
S32 inp_shift = 2 - inp_mv_pel;
S32 pred_shift; /* = 2 - ps_pred_ctxt->mv_pel; */
S32 ref_bits, cost;
S32 mv_p_x, mv_p_y;
S16 mvdx1, mvdx2, mvdy1, mvdy2;
i1_ref_idx = ps_node->i1_ref_idx;
ps_pred_nodes = &ps_pred_ctxt->as_pred_nodes[e_part_id];
ref_bits = ps_pred_ctxt->ppu1_ref_bits_tlu[ps_pred_ctxt->pred_lx][i1_ref_idx];
/*************************************************************************/
/* Priority to bottom left availability. Else we go to left. If both are */
/* not available, then a remains null */
/*************************************************************************/
if(ps_pred_nodes->ps_l->u1_is_avail)
{
i1_ref_l = ps_pred_nodes->ps_l->i1_ref_idx;
ps_pred_node_a = ps_pred_nodes->ps_l;
}
/*************************************************************************/
/* For encoder, top left may not be really needed unless we use slices, */
/* and even then in ME it may not be relevant. So we only consider T or */
/* TR, as, if both T and TR are not available, TL also will not be */
/*************************************************************************/
if((!(ps_pred_ctxt->proj_used) && (ps_pred_nodes->ps_tr->u1_is_avail)))
{
i1_ref_tr = ps_pred_nodes->ps_tr->i1_ref_idx;
ps_pred_node_b = ps_pred_nodes->ps_tr;
}
else
{
ps_pred_node_b = ps_pred_nodes->ps_coloc;
}
if(ps_pred_node_a == NULL)
{
ps_pred_node_a = ps_pred_nodes->ps_coloc;
if(ps_pred_node_b == ps_pred_nodes->ps_coloc)
ps_pred_node_b = ps_pred_nodes->ps_zeromv;
}
if(ps_pred_node_a->i1_ref_idx != i1_ref_idx)
{
SCALE_FOR_POC_DELTA(mv_p_x, mv_p_y, ps_pred_node_a, i1_ref_idx, ps_pred_ctxt->pi2_ref_scf);
}
else
{
mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
}
pred_shift = ps_pred_node_a->u1_subpel_done ? 0 : 2;
COMPUTE_DIFF_MV(mvdx1, mvdy1, ps_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
if(ps_pred_node_b->i1_ref_idx != i1_ref_idx)
{
SCALE_FOR_POC_DELTA(mv_p_x, mv_p_y, ps_pred_node_b, i1_ref_idx, ps_pred_ctxt->pi2_ref_scf);
}
else
{
mv_p_x = ps_pred_node_b->s_mv.i2_mvx;
mv_p_y = ps_pred_node_b->s_mv.i2_mvy;
}
pred_shift = ps_pred_node_b->u1_subpel_done ? 0 : 2;
COMPUTE_DIFF_MV(mvdx2, mvdy2, ps_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx2 = ABS(mvdx2);
mvdy2 = ABS(mvdy2);
if((mvdx1 + mvdy1) < (mvdx2 + mvdy2))
{
cost =
hme_get_range(mvdx1) + hme_get_range(mvdy1) + (mvdx1 > 0) + (mvdy1 > 0) + ref_bits + 2;
}
else
{
cost =
hme_get_range(mvdx2) + hme_get_range(mvdy2) + (mvdx2 > 0) + (mvdy2 > 0) + ref_bits + 2;
}
{
/* Part bits in Q1, so evaluate cost as ((mv_cost<<1) + partbitsQ1 + rnd)>>(q+1)*/
S32 rnd = 1 << (ps_pred_ctxt->lambda_q_shift - 1);
S32 tot_cost = (cost * ps_pred_ctxt->lambda);
return ((tot_cost + rnd) >> (ps_pred_ctxt->lambda_q_shift));
}
}
S32 compute_mv_cost_implicit_high_speed_modified(
search_node_t *ps_node, pred_ctxt_t *ps_pred_ctxt, PART_ID_T e_part_id, S32 inp_mv_pel)
{
search_node_t *ps_pred_node_a = NULL;
pred_candt_nodes_t *ps_pred_nodes;
S32 inp_shift = 2 - inp_mv_pel;
S32 pred_shift; /* = 2 - ps_pred_ctxt->mv_pel; */
S32 mv_p_x, mv_p_y;
S16 mvdx1, mvdy1;
S32 cost, ref_bits;
ps_pred_nodes = &ps_pred_ctxt->as_pred_nodes[e_part_id];
ref_bits = ps_pred_ctxt->ppu1_ref_bits_tlu[ps_pred_ctxt->pred_lx][ps_node->i1_ref_idx];
ps_pred_node_a = ps_pred_nodes->ps_mvp_node;
mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
pred_shift = ps_pred_node_a->u1_subpel_done ? 0 : 2;
COMPUTE_DIFF_MV(mvdx1, mvdy1, ps_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
cost = hme_get_range(mvdx1) + hme_get_range(mvdy1) + (mvdx1 > 0) + (mvdy1 > 0) + ref_bits + 2;
{
S32 rnd = 1 << (ps_pred_ctxt->lambda_q_shift - 1);
return ((cost * ps_pred_ctxt->lambda + rnd) >> ps_pred_ctxt->lambda_q_shift);
}
}
void hme_update_results_grid_pu_bestn_xtreme_speed(result_upd_prms_t *ps_result_prms)
{
/*The function modified with assumption that only 2NxN_B and Nx2N_R is modified */
search_node_t s_search_node_grid;
const search_node_t *ps_search_node_base;
search_node_t *ps_search_node_grid, *ps_best_node;
S32 i4_min_cost = (MAX_32BIT_VAL), i4_search_idx;
S32 num_results, i4_unique_id = -1, i4_grid_pt;
search_results_t *ps_search_results;
S32 *pi4_valid_part_ids;
S32 i4_step = ps_result_prms->i4_step;
S32 i4_grid_mask, i, i4_min_id;
S32 i4_tot_cost, i4_mv_cost, i4_sad, id;
S32 *pi4_sad_grid = ps_result_prms->pi4_sad_grid;
S32 grid_count = 0;
S32 pred_lx;
i4_min_id = (S32)PT_C;
i4_min_cost = MAX_32BIT_VAL;
ps_search_node_grid = &s_search_node_grid;
ps_search_node_base = ps_result_prms->ps_search_node_base;
*ps_search_node_grid = *ps_search_node_base;
pi4_valid_part_ids = ps_result_prms->pi4_valid_part_ids;
ps_search_results = ps_result_prms->ps_search_results;
num_results = (S32)ps_search_results->u1_num_results_per_part;
i4_grid_mask = ps_result_prms->i4_grid_mask;
for(i = 0; i < 9; i++)
{
if(i4_grid_mask & (1 << i))
grid_count++;
}
/* Some basic assumptions: only single pt, only part updates */
/* and more than 1 best result to be computed. */
//ASSERT(ps_result_prms->i4_grid_mask != 1);
//ASSERT(ps_result_prms->i4_part_mask != ENABLE_2Nx2N);
//ASSERT(ps_search_results->num_results > 1);
i4_search_idx = (S32)ps_result_prms->i1_ref_idx;
pred_lx = 1 - ps_search_results->pu1_is_past[i4_search_idx];
/*************************************************************************/
/* Supposing we do hte result update for a unique partid, we can */
/* store the best pt id in the grid and also min cost is return */
/* param. This will be useful for early exit cases. */
/* TODO : once we have separate fxn for unique part+grid, we can */
/* do away with this code here */
/*************************************************************************/
//if (pi4_valid_part_ids[1] == -1)
i4_unique_id = pi4_valid_part_ids[0];
/* pi4_valid_part_ids contains all the valid ids. We loop through */
/* this till we encounter -1. This is easier than having to */
/* figure out part by part, besides, active part decision is */
/* usually fixed for a given duration of search, e.g. entire fpel */
/* refinement for a blk/cu will use fixed valid part mask */
id = pi4_valid_part_ids[0];
/*****************************************************************/
/* points to the best search results corresponding to this */
/* specific part type. */
/*****************************************************************/
ps_best_node = ps_search_results->aps_part_results[i4_search_idx][id];
/*************************************************************************/
/* Outer loop runs through all active pts in the grid */
/*************************************************************************/
for(i4_grid_pt = 0; i4_grid_pt < (S32)NUM_GRID_PTS; i4_grid_pt++)
{
if(!(i4_grid_mask & (1 << i4_grid_pt)))
continue;
/* For the pt in the grid, update mvx and y depending on */
/* location of pt. Updates are in FPEL units. */
ps_search_node_grid->s_mv.i2_mvx = ps_search_node_base->s_mv.i2_mvx;
ps_search_node_grid->s_mv.i2_mvy = ps_search_node_base->s_mv.i2_mvy;
ps_search_node_grid->s_mv.i2_mvx += (S16)(i4_step * gai1_grid_id_to_x[i4_grid_pt]);
ps_search_node_grid->s_mv.i2_mvy += (S16)(i4_step * gai1_grid_id_to_y[i4_grid_pt]);
{
/* evaluate mv cost and totalcost for this part for this given mv*/
i4_mv_cost = compute_mv_cost_coarse_high_speed(
ps_search_node_grid,
&ps_search_results->as_pred_ctxt[pred_lx],
(PART_ID_T)id,
MV_RES_FPEL);
i4_sad = pi4_sad_grid[grid_count * id];
i4_tot_cost = i4_sad + i4_mv_cost;
ASSERT(i4_unique_id == id);
ASSERT(num_results == 1);
/*****************************************************************/
/* We do not labor through the results if the total cost worse */
/* than the last of the results. */
/*****************************************************************/
if(i4_tot_cost < ps_best_node[num_results - 1].i4_tot_cost)
{
i4_min_id = i4_grid_pt;
ps_result_prms->i4_min_cost = i4_tot_cost;
ps_best_node[0] = *ps_search_node_grid;
ps_best_node[0].i4_sad = i4_sad;
ps_best_node[0].i4_mv_cost = i4_mv_cost;
ps_best_node[0].i4_tot_cost = i4_tot_cost;
}
}
pi4_sad_grid++;
}
ps_result_prms->i4_min_id = i4_min_id;
}
void hme_update_results_grid_pu_bestn(result_upd_prms_t *ps_result_prms)
{
search_node_t s_search_node_grid;
const search_node_t *ps_search_node_base;
search_node_t *ps_search_node_grid, *ps_best_node;
S32 i4_min_cost = (MAX_32BIT_VAL), i4_search_idx;
S32 num_results, i4_unique_id = -1, i4_grid_pt;
search_results_t *ps_search_results;
S32 *pi4_valid_part_ids;
S32 i4_step = ps_result_prms->i4_step;
S32 i4_grid_mask, i4_count, i, i4_min_id;
S32 i4_tot_cost, i4_mv_cost, i4_sad, id;
S32 *pi4_sad_grid = ps_result_prms->pi4_sad_grid;
S32 grid_count = 0;
S32 pred_lx;
i4_min_id = (S32)PT_C;
i4_min_cost = MAX_32BIT_VAL;
ps_search_node_grid = &s_search_node_grid;
ps_search_node_base = ps_result_prms->ps_search_node_base;
*ps_search_node_grid = *ps_search_node_base;
pi4_valid_part_ids = ps_result_prms->pi4_valid_part_ids;
ps_search_results = ps_result_prms->ps_search_results;
num_results = (S32)ps_search_results->u1_num_results_per_part;
i4_grid_mask = ps_result_prms->i4_grid_mask;
for(i = 0; i < 9; i++)
{
if(i4_grid_mask & (1 << i))
{
grid_count++;
}
}
i4_search_idx = (S32)ps_result_prms->i1_ref_idx;
pred_lx = 1 - ps_search_results->pu1_is_past[i4_search_idx];
i4_unique_id = pi4_valid_part_ids[0];
/*************************************************************************/
/* Outer loop runs through all active pts in the grid */
/*************************************************************************/
for(i4_grid_pt = 0; i4_grid_pt < (S32)NUM_GRID_PTS; i4_grid_pt++)
{
if(!(i4_grid_mask & (1 << i4_grid_pt)))
{
continue;
}
/* For the pt in the grid, update mvx and y depending on */
/* location of pt. Updates are in FPEL units. */
ps_search_node_grid->s_mv.i2_mvx = ps_search_node_base->s_mv.i2_mvx;
ps_search_node_grid->s_mv.i2_mvy = ps_search_node_base->s_mv.i2_mvy;
ps_search_node_grid->s_mv.i2_mvx += (S16)(i4_step * gai1_grid_id_to_x[i4_grid_pt]);
ps_search_node_grid->s_mv.i2_mvy += (S16)(i4_step * gai1_grid_id_to_y[i4_grid_pt]);
i4_count = 0;
while((id = pi4_valid_part_ids[i4_count]) >= 0)
{
/*****************************************************************/
/* points to the best search results corresponding to this */
/* specific part type. */
/*****************************************************************/
ps_best_node = ps_search_results->aps_part_results[i4_search_idx][id];
/* evaluate mv cost and totalcost for this part for this given mv*/
i4_mv_cost = ps_result_prms->pf_mv_cost_compute(
ps_search_node_grid,
&ps_search_results->as_pred_ctxt[pred_lx],
(PART_ID_T)id,
MV_RES_FPEL);
i4_sad = pi4_sad_grid[grid_count * id];
i4_tot_cost = i4_sad + i4_mv_cost;
if(i4_unique_id == id)
{
if(i4_tot_cost < ps_result_prms->i4_min_cost)
{
i4_min_id = i4_grid_pt;
ps_result_prms->i4_min_cost = i4_tot_cost;
}
}
if(i4_tot_cost < ps_best_node[num_results - 1].i4_tot_cost)
{
for(i = 0; i < num_results - 1; i++)
{
if(i4_tot_cost < ps_best_node[i].i4_tot_cost)
{
memmove(
ps_best_node + i + 1,
ps_best_node + i,
sizeof(search_node_t) * (num_results - 1 - i));
break;
}
else if(i4_tot_cost == ps_best_node[i].i4_tot_cost)
{
if(0 == hme_cmp_nodes(ps_search_node_grid, ps_best_node + i))
break;
}
}
ps_best_node[i] = *ps_search_node_grid;
ps_best_node[i].i4_sad = i4_sad;
ps_best_node[i].i4_mv_cost = i4_mv_cost;
ps_best_node[i].i4_tot_cost = i4_tot_cost;
}
i4_count++;
}
pi4_sad_grid++;
}
ps_result_prms->i4_min_id = i4_min_id;
}
/**
********************************************************************************
* @fn hme_update_results_grid_pu_bestn_no_encode(result_upd_prms_t *ps_result_prms)
*
* @brief Updates results for the case where 1 best result is to be updated
* for a given pt, for several parts
* Note : The function is replicated for CLIPing the cost to 16bit to make
* bit match with SIMD version
*
* @param[in] result_upd_prms_t : Contains the input parameters to this fxn
*
* @return The result_upd_prms_t structure is updated for all the active
* parts in case the current candt has results for any given part
* that is the best result for that part
********************************************************************************
*/
void hme_update_results_grid_pu_bestn_no_encode(result_upd_prms_t *ps_result_prms)
{
search_node_t s_search_node_grid;
const search_node_t *ps_search_node_base;
search_node_t *ps_search_node_grid, *ps_best_node;
S32 i4_min_cost = (MAX_32BIT_VAL), i4_search_idx;
S32 num_results, i4_unique_id = -1, i4_grid_pt;
search_results_t *ps_search_results;
S32 *pi4_valid_part_ids;
S32 i4_step = ps_result_prms->i4_step;
S32 i4_grid_mask, i4_count, i, i4_min_id;
S32 i4_tot_cost, i4_mv_cost, i4_sad, id;
S32 *pi4_sad_grid = ps_result_prms->pi4_sad_grid;
S32 grid_count = 0;
S32 pred_lx;
i4_min_id = (S32)PT_C;
i4_min_cost = MAX_32BIT_VAL;
ps_search_node_grid = &s_search_node_grid;
ps_search_node_base = ps_result_prms->ps_search_node_base;
*ps_search_node_grid = *ps_search_node_base;
pi4_valid_part_ids = ps_result_prms->pi4_valid_part_ids;
ps_search_results = ps_result_prms->ps_search_results;
num_results = (S32)ps_search_results->u1_num_results_per_part;
i4_grid_mask = ps_result_prms->i4_grid_mask;
for(i = 0; i < 9; i++)
{
if(i4_grid_mask & (1 << i))
grid_count++;
}
/* Some basic assumptions: only single pt, only part updates */
/* and more than 1 best result to be computed. */
i4_search_idx = (S32)ps_result_prms->i1_ref_idx;
pred_lx = 1 - ps_search_results->pu1_is_past[i4_search_idx];
/*************************************************************************/
/* Supposing we do hte result update for a unique partid, we can */
/* store the best pt id in the grid and also min cost is return */
/* param. This will be useful for early exit cases. */
/* TODO : once we have separate fxn for unique part+grid, we can */
/* do away with this code here */
/*************************************************************************/
//if (pi4_valid_part_ids[1] == -1)
i4_unique_id = pi4_valid_part_ids[0];
/*************************************************************************/
/* Outer loop runs through all active pts in the grid */
/*************************************************************************/
for(i4_grid_pt = 0; i4_grid_pt < (S32)NUM_GRID_PTS; i4_grid_pt++)
{
if(!(i4_grid_mask & (1 << i4_grid_pt)))
continue;
/* For the pt in the grid, update mvx and y depending on */
/* location of pt. Updates are in FPEL units. */
ps_search_node_grid->s_mv.i2_mvx = ps_search_node_base->s_mv.i2_mvx;
ps_search_node_grid->s_mv.i2_mvy = ps_search_node_base->s_mv.i2_mvy;
ps_search_node_grid->s_mv.i2_mvx += (S16)(i4_step * gai1_grid_id_to_x[i4_grid_pt]);
ps_search_node_grid->s_mv.i2_mvy += (S16)(i4_step * gai1_grid_id_to_y[i4_grid_pt]);
i4_count = 0;
/* pi4_valid_part_ids contains all the valid ids. We loop through */
/* this till we encounter -1. This is easier than having to */
/* figure out part by part, besides, active part decision is */
/* usually fixed for a given duration of search, e.g. entire fpel */
/* refinement for a blk/cu will use fixed valid part mask */
while((id = pi4_valid_part_ids[i4_count]) >= 0)
{
//ps_search_node_grid->e_part_type = (PART_TYPE_T)id;
/*****************************************************************/
/* points to the best search results corresponding to this */
/* specific part type. */
/*****************************************************************/
ps_best_node = ps_search_results->aps_part_results[i4_search_idx][id];
/* evaluate mv cost and totalcost for this part for this given mv*/
i4_mv_cost = ps_result_prms->pf_mv_cost_compute(
ps_search_node_grid,
&ps_search_results->as_pred_ctxt[pred_lx],
(PART_ID_T)id,
MV_RES_FPEL);
i4_sad = pi4_sad_grid[grid_count * id];
/* Clipping to 16 bit to bit match with SIMD version */
i4_mv_cost = CLIP_S16(i4_mv_cost);
i4_sad = CLIP_S16(i4_sad);
i4_tot_cost = i4_sad + i4_mv_cost;
/* Clipping to 16 bit to bit match with SIMD version */
i4_tot_cost = CLIP_S16(i4_tot_cost);
if(i4_unique_id == id)
{
if(i4_tot_cost < ps_result_prms->i4_min_cost)
{
i4_min_id = i4_grid_pt;
ps_result_prms->i4_min_cost = i4_tot_cost;
}
}
/*****************************************************************/
/* We do not labor through the results if the total cost worse */
/* than the last of the results. */
/*****************************************************************/
if(i4_tot_cost < ps_best_node[num_results - 1].i4_tot_cost)
{
S32 eq_cost = 0;
/*************************************************************/
/* Identify where the current result isto be placed.Basically*/
/* find the node which has cost just higher thannodeundertest*/
/*************************************************************/
for(i = 0; i < num_results - 1; i++)
{
if(i4_tot_cost < ps_best_node[i].i4_tot_cost)
{
memmove(
ps_best_node + i + 1,
ps_best_node + i,
sizeof(search_node_t) * (num_results - 1 - i));
break;
}
else if(i4_tot_cost == ps_best_node[i].i4_tot_cost)
{
//if (0 == hme_cmp_nodes(ps_search_node_grid, ps_best_node+i))
// break;
/* When cost is same we comp. the nodes and if it's same skip. */
/* We don't want to add this code to intrinsic. So we are */
/* commenting it. The quality impact was minor when we did the */
/* regression. */
eq_cost = 1;
}
}
if(!eq_cost)
{
ps_best_node[i] = *ps_search_node_grid;
ps_best_node[i].i4_sad = i4_sad;
ps_best_node[i].i4_mv_cost = i4_mv_cost;
ps_best_node[i].i4_tot_cost = i4_tot_cost;
}
}
i4_count++;
}
pi4_sad_grid++;
}
ps_result_prms->i4_min_id = i4_min_id;
}
/**
********************************************************************************
* @fn hme_update_results_pt_npu_best1(result_upd_prms_t *ps_result_prms)
*
* @brief Updates results for the case where 1 best result is to be updated
* for a given pt, for several parts
*
* @param[in] ps_result_prms. Contains the input parameters to this fxn
* ::ps_pred_info : contains cost fxn ptr and predictor info
* ::pi4_sad : 17x9 SAD Grid, this case, only 1st 17 entries valid
* ::ps_search_results: Search results structure
* ::i1_ref_id : Reference index
* ::i4_grid_mask: Dont Care for this fxn
* ::pi4_valid_part_ids : valid part ids
* ::ps_search_node_base: Contains the centre pt candt info.
*
* @return The ps_search_results structure is updated for all the active
* parts in case the current candt has results for any given part
* that is the best result for that part
********************************************************************************
*/
void hme_update_results_pt_pu_best1_subpel_hs(
err_prms_t *ps_err_prms, result_upd_prms_t *ps_result_prms)
{
search_node_t *ps_search_node_base, *ps_best_node;
search_results_t *ps_search_results;
S32 id, i4_search_idx = ps_result_prms->u1_pred_lx;
S32 i4_count = 0, i4_sad, i4_mv_cost, i4_tot_cost;
S32 num_results, i;
S32 *pi4_valid_part_ids;
pi4_valid_part_ids = ps_result_prms->pi4_valid_part_ids;
/* Some basic assumptions: only single pt, only part updates */
/* and more than 1 best result to be computed. */
ASSERT(ps_result_prms->i4_grid_mask == 1);
ps_search_results = ps_result_prms->ps_search_results;
num_results = (S32)ps_search_results->u1_num_results_per_part;
/* Compute mv cost, total cost */
ps_search_node_base = (search_node_t *)ps_result_prms->ps_search_node_base;
while((id = pi4_valid_part_ids[i4_count]) >= 0)
{
S32 update_required = 1;
ps_best_node = ps_search_results->aps_part_results[i4_search_idx][id];
/* Use a pre-computed cost instead of freshly evaluating subpel cost */
i4_mv_cost = ps_best_node->i4_mv_cost;
i4_sad = ps_result_prms->pi4_sad_grid[id];
i4_tot_cost = i4_sad + i4_mv_cost;
/* We do not labor through the results if the total cost is worse than */
/* the last of the results. */
if(i4_tot_cost < ps_best_node[num_results - 1].i4_tot_cost)
{
/* Identify where the current result is to be placed. Basically find */
/* the node which has cost just higher than node under test */
for(i = 0; i < num_results - 1; i++)
{
if(ps_best_node[i].i1_ref_idx != -1)
{
if(i4_tot_cost < ps_best_node[i].i4_tot_cost)
{
memmove(
ps_best_node + i + 1,
ps_best_node + i,
sizeof(search_node_t) * (num_results - 1 - i));
break;
}
else if(i4_tot_cost == ps_best_node[i].i4_tot_cost)
{
update_required = 0;
break;
}
}
else
{
break;
}
}
if(update_required)
{
/* Update when either ref_idx or mv's are different */
ps_best_node[i] = *ps_search_node_base;
ps_best_node[i].i4_sad = i4_sad;
ps_best_node[i].i4_mv_cost = i4_mv_cost;
ps_best_node[i].i4_tot_cost = i4_tot_cost;
}
}
i4_count++;
}
}
void hme_update_results_pt_pu_best1_subpel_hs_1(
err_prms_t *ps_err_prms, result_upd_prms_t *ps_result_prms)
{
search_node_t *ps_search_node_base, *ps_best_node;
search_results_t *ps_search_results;
S32 id, i4_search_idx = ps_result_prms->u1_pred_lx;
S32 i4_count = 0, i4_sad, i4_mv_cost, i4_tot_cost;
S32 num_results;
S32 *pi4_valid_part_ids;
pi4_valid_part_ids = ps_result_prms->pi4_valid_part_ids;
/* Some basic assumptions: only single pt, only part updates */
/* and more than 1 best result to be computed. */
ASSERT(ps_result_prms->i4_grid_mask == 1);
ps_search_results = ps_result_prms->ps_search_results;
num_results = (S32)ps_search_results->u1_num_results_per_part;
/* Compute mv cost, total cost */
ps_search_node_base = (search_node_t *)ps_result_prms->ps_search_node_base;
while((id = pi4_valid_part_ids[i4_count]) >= 0)
{
S32 update_required = 0;
ps_best_node = ps_search_results->aps_part_results[i4_search_idx][id];
/* Use a pre-computed cost instead of freshly evaluating subpel cost */
i4_mv_cost = ps_best_node->i4_mv_cost;
i4_sad = ps_result_prms->pi4_sad_grid[id];
i4_tot_cost = i4_sad + i4_mv_cost;
/* We do not labor through the results if the total cost is worse than */
/* the last of the results. */
if(i4_tot_cost < ps_best_node[1].i4_tot_cost)
{
S32 sdi_value = 0;
update_required = 2;
/* Identify where the current result is to be placed. Basically find */
/* the node which has cost just higher than node under test */
{
if(i4_tot_cost < ps_best_node[0].i4_tot_cost)
{
update_required = 1;
sdi_value = ps_best_node[0].i4_sad - i4_sad;
}
else if(
(ps_result_prms->i2_mv_x == ps_best_node[0].s_mv.i2_mvx) &&
(ps_result_prms->i2_mv_y == ps_best_node[0].s_mv.i2_mvy) &&
(ps_best_node[0].i1_ref_idx == ps_result_prms->i1_ref_idx))
{
update_required = 0;
}
}
if(update_required == 2)
{
subpel_refine_ctxt_t *ps_subpel_refine_ctxt = ps_result_prms->ps_subpel_refine_ctxt;
ps_subpel_refine_ctxt->i2_tot_cost[1][i4_count] = i4_tot_cost;
ps_subpel_refine_ctxt->i2_mv_cost[1][i4_count] = i4_mv_cost;
ps_subpel_refine_ctxt->i2_mv_x[1][i4_count] = ps_result_prms->i2_mv_x;
ps_subpel_refine_ctxt->i2_mv_y[1][i4_count] = ps_result_prms->i2_mv_y;
ps_subpel_refine_ctxt->i2_ref_idx[1][i4_count] = ps_result_prms->i1_ref_idx;
}
else if(update_required == 1)
{
subpel_refine_ctxt_t *ps_subpel_refine_ctxt = ps_result_prms->ps_subpel_refine_ctxt;
ps_subpel_refine_ctxt->i2_tot_cost[1][i4_count] =
ps_subpel_refine_ctxt->i2_tot_cost[0][i4_count];
ps_subpel_refine_ctxt->i2_mv_cost[1][i4_count] =
ps_subpel_refine_ctxt->i2_mv_cost[0][i4_count];
ps_subpel_refine_ctxt->i2_mv_x[1][i4_count] =
ps_subpel_refine_ctxt->i2_mv_x[0][i4_count];
ps_subpel_refine_ctxt->i2_mv_y[1][i4_count] =
ps_subpel_refine_ctxt->i2_mv_y[0][i4_count];
ps_subpel_refine_ctxt->i2_ref_idx[1][i4_count] =
ps_subpel_refine_ctxt->i2_ref_idx[0][i4_count];
ps_subpel_refine_ctxt->i2_tot_cost[0][i4_count] = i4_tot_cost;
ps_subpel_refine_ctxt->i2_mv_cost[0][i4_count] = i4_mv_cost;
ps_subpel_refine_ctxt->i2_mv_x[0][i4_count] = ps_result_prms->i2_mv_x;
ps_subpel_refine_ctxt->i2_mv_y[0][i4_count] = ps_result_prms->i2_mv_y;
ps_subpel_refine_ctxt->i2_ref_idx[0][i4_count] = ps_result_prms->i1_ref_idx;
}
}
i4_count++;
}
}
/**
******************************************************************************
* @brief Gives a result fxn ptr for a index [x] where x is as:
* 0 : single pt, no partial updates, 1 best result
* 1 : single pt, no partial updates, N best results
* 2 : single pt, partial updates, 1 best result
* 3 : single pt, partial updates, N best results
* 0 : grid , no partial updates, 1 best result
* 1 : grid , no partial updates, N best results
* 2 : grid , partial updates, 1 best result
* 3 : grid , partial updates, N best results
******************************************************************************
*/
static PF_RESULT_FXN_T g_pf_result_fxn[8] = { UPD_RES_PT_NPU_BEST1, UPD_RES_PT_NPU_BESTN,
UPD_RES_PT_PU_BEST1, UPD_RES_PT_PU_BESTN,
UPD_RES_GRID_NPU_BEST1, UPD_RES_GRID_NPU_BESTN,
UPD_RES_GRID_PU_BEST1, UPD_RES_GRID_PU_BESTN };
/**
********************************************************************************
* @fn hme_get_result_fxn(i4_grid_mask, i4_part_mask, i4_num_results)
*
* @brief Obtains the suitable result function that evaluates COST and also
* computes one or more best results for point/grid, single part or
* more than one part.
*
* @param[in] i4_grid_mask : Mask containing which of 9 grid pts active
*
* @param[in] i4_part_mask : Mask containing which of the 17 parts active
*
* @param[in] i4_num_results: Number of active results
*
* @return Pointer to the appropriate result update function
********************************************************************************
*/
PF_RESULT_FXN_T hme_get_result_fxn(S32 i4_grid_mask, S32 i4_part_mask, S32 i4_num_results)
{
S32 i4_is_grid = (i4_grid_mask != 1);
S32 i4_is_pu = ((i4_part_mask & (i4_part_mask - 1)) != 0);
S32 i4_res_gt1 = (i4_num_results > 1);
S32 id;
id = (i4_is_grid << 2) + (i4_is_pu << 1) + i4_res_gt1;
return (g_pf_result_fxn[id]);
}
void hme_calc_sad_and_2_best_results(
hme_search_prms_t *ps_search_prms,
wgt_pred_ctxt_t *ps_wt_inp_prms,
err_prms_t *ps_err_prms,
result_upd_prms_t *ps_result_prms,
U08 **ppu1_ref,
S32 i4_ref_stride)
{
S32 i4_candt;
S32 i4_inp_off;
S32 i4_ref_offset;
S32 i4_num_nodes;
S32 *pi4_sad_grid = ps_err_prms->pi4_sad_grid;
S32 cur_buf_stride = ps_err_prms->i4_inp_stride;
WORD32 ref_buf_stride = ps_err_prms->i4_ref_stride;
WORD32 cur_buf_stride_ls2 = (cur_buf_stride << 2);
WORD32 ref_buf_stride_ls2 = (ref_buf_stride << 2);
mv_refine_ctxt_t *ps_mv_refine_ctxt;
search_node_t *ps_search_node;
ps_mv_refine_ctxt = ps_search_prms->ps_fullpel_refine_ctxt;
i4_num_nodes = ps_search_prms->i4_num_search_nodes;
i4_inp_off = ps_search_prms->i4_cu_x_off;
i4_inp_off += ps_search_prms->i4_cu_y_off * cur_buf_stride;
i4_ref_offset = (i4_ref_stride * ps_search_prms->i4_y_off) + ps_search_prms->i4_x_off;
ps_search_node = ps_search_prms->ps_search_nodes;
for(i4_candt = 0; i4_candt < i4_num_nodes; i4_candt++)
{
/**********************************************************************/
/* CALL THE FUNCTION THAT COMPUTES THE SAD AND UPDATES THE SAD GRID */
/**********************************************************************/
{
WORD32 b, c, d;
UWORD8 *pu1_cur_ptr;
UWORD8 *pu1_ref_ptr;
UWORD16 au2_4x4_sad[NUM_4X4];
if(ps_search_node->s_mv.i2_mvx == INTRA_MV)
{
continue;
}
ps_err_prms->pu1_inp =
ps_wt_inp_prms->apu1_wt_inp[ps_search_node->i1_ref_idx] + i4_inp_off;
ps_err_prms->pu1_ref = ppu1_ref[ps_search_node->i1_ref_idx] + i4_ref_offset;
ps_err_prms->pu1_ref += ps_search_node->s_mv.i2_mvx;
ps_err_prms->pu1_ref += (ps_search_node->s_mv.i2_mvy * i4_ref_stride);
pu1_cur_ptr = ps_err_prms->pu1_inp;
pu1_ref_ptr = &ps_err_prms->pu1_ref[0];
/* Loop to compute the SAD's */
{
memset(&au2_4x4_sad[0], 0, NUM_4X4 * sizeof(UWORD16));
for(b = 0; b < NUM_4X4; b++)
{
WORD32 t1 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * cur_buf_stride_ls2;
WORD32 t2 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * ref_buf_stride_ls2;
for(c = 0; c < NUM_ROWS_IN_4X4; c++)
{
WORD32 z_cur = (cur_buf_stride)*c + t1;
WORD32 z_ref = (ref_buf_stride)*c + t2;
for(d = 0; d < NUM_PIXELS_IN_ROW; d++)
{
au2_4x4_sad[b] += (UWORD16)ABS((
((S32)pu1_ref_ptr[(z_ref + d)]) - ((S32)pu1_cur_ptr[(z_cur + d)])));
}
}
}
pi4_sad_grid[PART_ID_NxN_TL] =
(au2_4x4_sad[0] + au2_4x4_sad[1] + au2_4x4_sad[4] + au2_4x4_sad[5]);
pi4_sad_grid[PART_ID_NxN_TR] =
(au2_4x4_sad[2] + au2_4x4_sad[3] + au2_4x4_sad[6] + au2_4x4_sad[7]);
pi4_sad_grid[PART_ID_NxN_BL] =
(au2_4x4_sad[8] + au2_4x4_sad[9] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_NxN_BR] =
(au2_4x4_sad[10] + au2_4x4_sad[11] + au2_4x4_sad[14] + au2_4x4_sad[15]);
pi4_sad_grid[PART_ID_Nx2N_L] =
pi4_sad_grid[PART_ID_NxN_TL] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_Nx2N_R] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_BR];
pi4_sad_grid[PART_ID_2NxN_T] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_TL];
pi4_sad_grid[PART_ID_2NxN_B] =
pi4_sad_grid[PART_ID_NxN_BR] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_nLx2N_L] =
(au2_4x4_sad[8] + au2_4x4_sad[0] + au2_4x4_sad[12] + au2_4x4_sad[4]);
pi4_sad_grid[PART_ID_nRx2N_R] =
(au2_4x4_sad[3] + au2_4x4_sad[7] + au2_4x4_sad[15] + au2_4x4_sad[11]);
pi4_sad_grid[PART_ID_2NxnU_T] =
(au2_4x4_sad[1] + au2_4x4_sad[0] + au2_4x4_sad[2] + au2_4x4_sad[3]);
pi4_sad_grid[PART_ID_2NxnD_B] =
(au2_4x4_sad[15] + au2_4x4_sad[14] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_2Nx2N] =
pi4_sad_grid[PART_ID_2NxN_T] + pi4_sad_grid[PART_ID_2NxN_B];
pi4_sad_grid[PART_ID_2NxnU_B] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnU_T];
pi4_sad_grid[PART_ID_2NxnD_T] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnD_B];
pi4_sad_grid[PART_ID_nRx2N_L] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nRx2N_R];
pi4_sad_grid[PART_ID_nLx2N_R] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nLx2N_L];
}
}
{
S32 i4_count = 0, i4_sad, i4_mv_cost, i4_tot_cost;
S32 *pi4_valid_part_ids = &ps_mv_refine_ctxt->ai4_part_id[0];
S32 best_node_cost;
S32 second_best_node_cost;
{
S16 mvdx1, mvdy1;
S32 i4_search_idx = (S32)ps_result_prms->i1_ref_idx;
search_results_t *ps_search_results = ps_result_prms->ps_search_results;
S32 pred_lx = i4_search_idx;
pred_ctxt_t *ps_pred_ctxt = &ps_search_results->as_pred_ctxt[pred_lx];
pred_candt_nodes_t *ps_pred_nodes = &ps_pred_ctxt->as_pred_nodes[PART_2Nx2N];
search_node_t *ps_pred_node_a = ps_pred_nodes->ps_mvp_node;
S32 inp_shift = 2;
S32 pred_shift = ps_pred_node_a->u1_subpel_done ? 0 : 2;
S32 lambda_q_shift = ps_pred_ctxt->lambda_q_shift;
S32 lambda = ps_pred_ctxt->lambda;
S32 rnd = 1 << (lambda_q_shift - 1);
S32 mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
S32 mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
S32 ref_bits =
ps_pred_ctxt
->ppu1_ref_bits_tlu[ps_pred_ctxt->pred_lx][ps_search_node->i1_ref_idx];
COMPUTE_DIFF_MV(
mvdx1, mvdy1, ps_search_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
i4_mv_cost = hme_get_range(mvdx1) + hme_get_range(mvdy1) + (mvdx1 > 0) +
(mvdy1 > 0) + ref_bits + 2;
i4_mv_cost *= lambda;
i4_mv_cost += rnd;
i4_mv_cost >>= lambda_q_shift;
i4_mv_cost = CLIP_U16(i4_mv_cost);
}
/*For each valid partition, update the refine_prm structure to reflect the best and second
best candidates for that partition*/
for(i4_count = 0; i4_count < ps_mv_refine_ctxt->i4_num_valid_parts; i4_count++)
{
S32 update_required = 0;
S32 part_id = pi4_valid_part_ids[i4_count];
S32 index = (ps_mv_refine_ctxt->i4_num_valid_parts > 8) ? part_id : i4_count;
/*Calculate total cost*/
i4_sad = CLIP3(pi4_sad_grid[part_id], 0, 0x7fff);
i4_tot_cost = CLIP_S16(i4_sad + i4_mv_cost);
/*****************************************************************/
/* We do not labor through the results if the total cost worse */
/* than the last of the results. */
/*****************************************************************/
best_node_cost = CLIP_S16(ps_mv_refine_ctxt->i2_tot_cost[0][index]);
second_best_node_cost = CLIP_S16(ps_mv_refine_ctxt->i2_tot_cost[1][index]);
if(i4_tot_cost < second_best_node_cost)
{
update_required = 2;
/*************************************************************/
/* Identify where the current result isto be placed.Basically*/
/* find the node which has cost just higher thannodeundertest*/
/*************************************************************/
if(i4_tot_cost < best_node_cost)
{
update_required = 1;
}
else if(i4_tot_cost == best_node_cost)
{
update_required = 0;
}
if(update_required == 2)
{
ps_mv_refine_ctxt->i2_tot_cost[1][index] = i4_tot_cost;
ps_mv_refine_ctxt->i2_mv_cost[1][index] = i4_mv_cost;
ps_mv_refine_ctxt->i2_mv_x[1][index] = ps_search_node->s_mv.i2_mvx;
ps_mv_refine_ctxt->i2_mv_y[1][index] = ps_search_node->s_mv.i2_mvy;
ps_mv_refine_ctxt->i2_ref_idx[1][index] = ps_search_node->i1_ref_idx;
}
else if(update_required == 1)
{
ps_mv_refine_ctxt->i2_tot_cost[1][index] =
ps_mv_refine_ctxt->i2_tot_cost[0][index];
ps_mv_refine_ctxt->i2_mv_cost[1][index] =
ps_mv_refine_ctxt->i2_mv_cost[0][index];
ps_mv_refine_ctxt->i2_mv_x[1][index] = ps_mv_refine_ctxt->i2_mv_x[0][index];
ps_mv_refine_ctxt->i2_mv_y[1][index] = ps_mv_refine_ctxt->i2_mv_y[0][index];
ps_mv_refine_ctxt->i2_ref_idx[1][index] =
ps_mv_refine_ctxt->i2_ref_idx[0][index];
ps_mv_refine_ctxt->i2_tot_cost[0][index] = i4_tot_cost;
ps_mv_refine_ctxt->i2_mv_cost[0][index] = i4_mv_cost;
ps_mv_refine_ctxt->i2_mv_x[0][index] = ps_search_node->s_mv.i2_mvx;
ps_mv_refine_ctxt->i2_mv_y[0][index] = ps_search_node->s_mv.i2_mvy;
ps_mv_refine_ctxt->i2_ref_idx[0][index] = ps_search_node->i1_ref_idx;
}
}
}
}
ps_search_node++;
}
{
WORD32 i4_i;
WORD32 part_id;
search_node_t *ps_search_node = ps_search_prms->ps_search_nodes;
for(i4_i = 0; i4_i < ps_mv_refine_ctxt->i4_num_valid_parts; i4_i++)
{
part_id = ps_mv_refine_ctxt->ai4_part_id[i4_i];
if(ps_mv_refine_ctxt->i2_tot_cost[0][part_id] >= MAX_SIGNED_16BIT_VAL)
{
ASSERT(ps_mv_refine_ctxt->i2_mv_cost[0][part_id] == MAX_SIGNED_16BIT_VAL);
ASSERT(ps_mv_refine_ctxt->i2_mv_x[0][part_id] == 0);
ASSERT(ps_mv_refine_ctxt->i2_mv_y[0][part_id] == 0);
ps_mv_refine_ctxt->i2_ref_idx[0][part_id] = ps_search_node->i1_ref_idx;
}
if(ps_mv_refine_ctxt->i2_tot_cost[1][part_id] >= MAX_SIGNED_16BIT_VAL)
{
ASSERT(ps_mv_refine_ctxt->i2_mv_cost[1][part_id] == MAX_SIGNED_16BIT_VAL);
ASSERT(ps_mv_refine_ctxt->i2_mv_x[1][part_id] == 0);
ASSERT(ps_mv_refine_ctxt->i2_mv_y[1][part_id] == 0);
ps_mv_refine_ctxt->i2_ref_idx[1][part_id] = ps_search_node->i1_ref_idx;
}
}
}
}
void hme_calc_sad_and_2_best_results_subpel(
err_prms_t *ps_err_prms, result_upd_prms_t *ps_result_prms)
{
S32 i4_candt;
S32 i4_num_nodes;
S32 *pi4_sad_grid = ps_err_prms->pi4_sad_grid;
S32 cur_buf_stride = ps_err_prms->i4_inp_stride;
WORD32 ref_buf_stride = ps_err_prms->i4_ref_stride;
WORD32 cur_buf_stride_ls2 = (cur_buf_stride << 2);
WORD32 ref_buf_stride_ls2 = (ref_buf_stride << 2);
mv_refine_ctxt_t *ps_subpel_refine_ctxt;
ps_subpel_refine_ctxt = ps_result_prms->ps_subpel_refine_ctxt;
i4_num_nodes = 1;
/* Run through each of the candts in a loop */
for(i4_candt = 0; i4_candt < i4_num_nodes; i4_candt++)
{
/**********************************************************************/
/* CALL THE FUNCTION THAT COMPUTES THE SAD AND UPDATES THE SAD GRID */
/**********************************************************************/
{
WORD32 b, c, d;
UWORD8 *pu1_cur_ptr;
UWORD8 *pu1_ref_ptr;
UWORD16 au2_4x4_sad[NUM_4X4];
pu1_cur_ptr = ps_err_prms->pu1_inp;
pu1_ref_ptr = &ps_err_prms->pu1_ref[0];
/* Loop to compute the SAD's */
{
memset(&au2_4x4_sad[0], 0, NUM_4X4 * sizeof(UWORD16));
for(b = 0; b < NUM_4X4; b++)
{
WORD32 t1 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * cur_buf_stride_ls2;
WORD32 t2 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * ref_buf_stride_ls2;
for(c = 0; c < NUM_ROWS_IN_4X4; c++)
{
WORD32 z_cur = (cur_buf_stride)*c + t1;
WORD32 z_ref = (ref_buf_stride)*c + t2;
for(d = 0; d < NUM_PIXELS_IN_ROW; d++)
{
au2_4x4_sad[b] += (UWORD16)ABS((
((S32)pu1_ref_ptr[(z_ref + d)]) - ((S32)pu1_cur_ptr[(z_cur + d)])));
}
}
}
pi4_sad_grid[PART_ID_NxN_TL] =
(au2_4x4_sad[0] + au2_4x4_sad[1] + au2_4x4_sad[4] + au2_4x4_sad[5]);
pi4_sad_grid[PART_ID_NxN_TR] =
(au2_4x4_sad[2] + au2_4x4_sad[3] + au2_4x4_sad[6] + au2_4x4_sad[7]);
pi4_sad_grid[PART_ID_NxN_BL] =
(au2_4x4_sad[8] + au2_4x4_sad[9] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_NxN_BR] =
(au2_4x4_sad[10] + au2_4x4_sad[11] + au2_4x4_sad[14] + au2_4x4_sad[15]);
pi4_sad_grid[PART_ID_Nx2N_L] =
pi4_sad_grid[PART_ID_NxN_TL] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_Nx2N_R] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_BR];
pi4_sad_grid[PART_ID_2NxN_T] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_TL];
pi4_sad_grid[PART_ID_2NxN_B] =
pi4_sad_grid[PART_ID_NxN_BR] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_nLx2N_L] =
(au2_4x4_sad[8] + au2_4x4_sad[0] + au2_4x4_sad[12] + au2_4x4_sad[4]);
pi4_sad_grid[PART_ID_nRx2N_R] =
(au2_4x4_sad[3] + au2_4x4_sad[7] + au2_4x4_sad[15] + au2_4x4_sad[11]);
pi4_sad_grid[PART_ID_2NxnU_T] =
(au2_4x4_sad[1] + au2_4x4_sad[0] + au2_4x4_sad[2] + au2_4x4_sad[3]);
pi4_sad_grid[PART_ID_2NxnD_B] =
(au2_4x4_sad[15] + au2_4x4_sad[14] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_2Nx2N] =
pi4_sad_grid[PART_ID_2NxN_T] + pi4_sad_grid[PART_ID_2NxN_B];
pi4_sad_grid[PART_ID_2NxnU_B] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnU_T];
pi4_sad_grid[PART_ID_2NxnD_T] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnD_B];
pi4_sad_grid[PART_ID_nRx2N_L] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nRx2N_R];
pi4_sad_grid[PART_ID_nLx2N_R] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nLx2N_L];
}
}
/**********************************************************************/
/* CALL THE FUNCTION THAT COMPUTES UPDATES THE BEST RESULTS */
/**********************************************************************/
{
S32 i4_count = 0, i4_sad, i4_mv_cost, i4_tot_cost;
S32 *pi4_valid_part_ids = &ps_subpel_refine_ctxt->ai4_part_id[0];
S32 best_node_cost;
S32 second_best_node_cost;
/*For each valid partition, update the refine_prm structure to reflect the best and second
best candidates for that partition*/
for(i4_count = 0; i4_count < ps_subpel_refine_ctxt->i4_num_valid_parts; i4_count++)
{
S32 update_required = 0;
S32 part_id = pi4_valid_part_ids[i4_count];
S32 index = (ps_subpel_refine_ctxt->i4_num_valid_parts > 8) ? part_id : i4_count;
/* Use a pre-computed cost instead of freshly evaluating subpel cost */
i4_mv_cost = ps_subpel_refine_ctxt->i2_mv_cost[0][index];
/*Calculate total cost*/
i4_sad = CLIP3(pi4_sad_grid[part_id], 0, 0x7fff);
i4_tot_cost = CLIP_S16(i4_sad + i4_mv_cost);
/*****************************************************************/
/* We do not labor through the results if the total cost worse */
/* than the last of the results. */
/*****************************************************************/
best_node_cost = CLIP_S16(ps_subpel_refine_ctxt->i2_tot_cost[0][index]);
second_best_node_cost = CLIP_S16(ps_subpel_refine_ctxt->i2_tot_cost[1][index]);
if(i4_tot_cost < second_best_node_cost)
{
update_required = 2;
/*************************************************************/
/* Identify where the current result isto be placed.Basically*/
/* find the node which has cost just higher thannodeundertest*/
/*************************************************************/
if(i4_tot_cost < best_node_cost)
{
update_required = 1;
}
else if(i4_tot_cost == ps_subpel_refine_ctxt->i2_tot_cost[0][index])
{
update_required = 0;
}
if(update_required == 2)
{
ps_subpel_refine_ctxt->i2_tot_cost[1][index] = i4_tot_cost;
ps_subpel_refine_ctxt->i2_mv_cost[1][index] = i4_mv_cost;
ps_subpel_refine_ctxt->i2_mv_x[1][index] = ps_result_prms->i2_mv_x;
ps_subpel_refine_ctxt->i2_mv_y[1][index] = ps_result_prms->i2_mv_y;
ps_subpel_refine_ctxt->i2_ref_idx[1][index] = ps_result_prms->i1_ref_idx;
}
else if(update_required == 1)
{
ps_subpel_refine_ctxt->i2_tot_cost[1][index] =
ps_subpel_refine_ctxt->i2_tot_cost[0][index];
ps_subpel_refine_ctxt->i2_mv_cost[1][index] =
ps_subpel_refine_ctxt->i2_mv_cost[0][index];
ps_subpel_refine_ctxt->i2_mv_x[1][index] =
ps_subpel_refine_ctxt->i2_mv_x[0][index];
ps_subpel_refine_ctxt->i2_mv_y[1][index] =
ps_subpel_refine_ctxt->i2_mv_y[0][index];
ps_subpel_refine_ctxt->i2_ref_idx[1][index] =
ps_subpel_refine_ctxt->i2_ref_idx[0][index];
ps_subpel_refine_ctxt->i2_tot_cost[0][index] = i4_tot_cost;
ps_subpel_refine_ctxt->i2_mv_cost[0][index] = i4_mv_cost;
ps_subpel_refine_ctxt->i2_mv_x[0][index] = ps_result_prms->i2_mv_x;
ps_subpel_refine_ctxt->i2_mv_y[0][index] = ps_result_prms->i2_mv_y;
ps_subpel_refine_ctxt->i2_ref_idx[0][index] = ps_result_prms->i1_ref_idx;
}
}
}
}
}
{
WORD32 i4_count = 0;
for(i4_count = 0; i4_count < TOT_NUM_PARTS; i4_count++)
{
WORD32 j;
for(j = 0; j < 2; j++)
{
if(ps_subpel_refine_ctxt->i2_tot_cost[j][i4_count] >= MAX_SIGNED_16BIT_VAL)
{
ps_subpel_refine_ctxt->ai2_fullpel_satd[j][i4_count] = MAX_SIGNED_16BIT_VAL;
}
}
}
}
}
void hme_calc_stim_injected_sad_and_2_best_results(
hme_search_prms_t *ps_search_prms,
wgt_pred_ctxt_t *ps_wt_inp_prms,
err_prms_t *ps_err_prms,
result_upd_prms_t *ps_result_prms,
U08 **ppu1_ref,
S32 i4_ref_stride)
{
mv_refine_ctxt_t *ps_mv_refine_ctxt;
search_node_t *ps_search_node;
S32 i4_candt;
S32 i4_count;
S32 i4_inp_off;
S32 i4_ref_offset;
S32 i4_num_nodes;
ULWORD64 *au8_final_src_sigmaX, *au8_final_src_sigmaXSquared, au8_final_ref_sigmaX[17],
au8_final_ref_sigmaXSquared[17];
UWORD32 au4_4x4_ref_sigmaX[NUM_4X4], au4_4x4_ref_sigmaXSquared[NUM_4X4];
S32 *pi4_valid_part_ids;
S32 *pi4_sad_grid = ps_err_prms->pi4_sad_grid;
S32 cur_buf_stride = ps_err_prms->i4_inp_stride;
WORD32 ref_buf_stride = ps_err_prms->i4_ref_stride;
WORD32 cur_buf_stride_ls2 = (cur_buf_stride << 2);
WORD32 ref_buf_stride_ls2 = (ref_buf_stride << 2);
ps_mv_refine_ctxt = ps_search_prms->ps_fullpel_refine_ctxt;
i4_num_nodes = ps_search_prms->i4_num_search_nodes;
i4_inp_off = ps_search_prms->i4_cu_x_off;
i4_inp_off += ps_search_prms->i4_cu_y_off * cur_buf_stride;
i4_ref_offset = (i4_ref_stride * ps_search_prms->i4_y_off) + ps_search_prms->i4_x_off;
ps_search_node = ps_search_prms->ps_search_nodes;
pi4_valid_part_ids = &ps_mv_refine_ctxt->ai4_part_id[0];
/* Set local pointer to point to partition level sigma values calculated in hme_refine */
au8_final_src_sigmaX = ps_search_prms->pu8_part_src_sigmaX;
au8_final_src_sigmaXSquared = ps_search_prms->pu8_part_src_sigmaXSquared;
for(i4_candt = 0; i4_candt < i4_num_nodes; i4_candt++)
{
{
WORD32 b, c, d;
UWORD8 *pu1_cur_ptr;
UWORD8 *pu1_ref_ptr;
UWORD16 au2_4x4_sad[NUM_4X4];
if(ps_search_node->s_mv.i2_mvx == INTRA_MV)
{
continue;
}
ps_err_prms->pu1_inp =
ps_wt_inp_prms->apu1_wt_inp[ps_search_node->i1_ref_idx] + i4_inp_off;
ps_err_prms->pu1_ref = ppu1_ref[ps_search_node->i1_ref_idx] + i4_ref_offset;
ps_err_prms->pu1_ref += ps_search_node->s_mv.i2_mvx;
ps_err_prms->pu1_ref += (ps_search_node->s_mv.i2_mvy * i4_ref_stride);
pu1_cur_ptr = ps_err_prms->pu1_inp;
pu1_ref_ptr = &ps_err_prms->pu1_ref[0];
/* Loop to compute the SAD's */
{
memset(&au2_4x4_sad[0], 0, NUM_4X4 * sizeof(UWORD16));
for(b = 0; b < NUM_4X4; b++)
{
WORD32 t1 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * cur_buf_stride_ls2;
WORD32 t2 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * ref_buf_stride_ls2;
for(c = 0; c < NUM_ROWS_IN_4X4; c++)
{
WORD32 z_cur = (cur_buf_stride)*c + t1;
WORD32 z_ref = (ref_buf_stride)*c + t2;
for(d = 0; d < NUM_PIXELS_IN_ROW; d++)
{
au2_4x4_sad[b] += (UWORD16)ABS((
((S32)pu1_ref_ptr[(z_ref + d)]) - ((S32)pu1_cur_ptr[(z_cur + d)])));
}
}
}
/* Compute sigmaX and sigmaX_Squared at 4x4 level for ref from ref_ptr */
hme_compute_sigmaX_and_sigmaXSquared(
pu1_ref_ptr,
ref_buf_stride,
au4_4x4_ref_sigmaX,
au4_4x4_ref_sigmaXSquared,
4,
4,
16,
16,
1,
4);
pi4_sad_grid[PART_ID_NxN_TL] =
(au2_4x4_sad[0] + au2_4x4_sad[1] + au2_4x4_sad[4] + au2_4x4_sad[5]);
pi4_sad_grid[PART_ID_NxN_TR] =
(au2_4x4_sad[2] + au2_4x4_sad[3] + au2_4x4_sad[6] + au2_4x4_sad[7]);
pi4_sad_grid[PART_ID_NxN_BL] =
(au2_4x4_sad[8] + au2_4x4_sad[9] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_NxN_BR] =
(au2_4x4_sad[10] + au2_4x4_sad[11] + au2_4x4_sad[14] + au2_4x4_sad[15]);
pi4_sad_grid[PART_ID_Nx2N_L] =
pi4_sad_grid[PART_ID_NxN_TL] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_Nx2N_R] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_BR];
pi4_sad_grid[PART_ID_2NxN_T] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_TL];
pi4_sad_grid[PART_ID_2NxN_B] =
pi4_sad_grid[PART_ID_NxN_BR] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_nLx2N_L] =
(au2_4x4_sad[8] + au2_4x4_sad[0] + au2_4x4_sad[12] + au2_4x4_sad[4]);
pi4_sad_grid[PART_ID_nRx2N_R] =
(au2_4x4_sad[3] + au2_4x4_sad[7] + au2_4x4_sad[15] + au2_4x4_sad[11]);
pi4_sad_grid[PART_ID_2NxnU_T] =
(au2_4x4_sad[1] + au2_4x4_sad[0] + au2_4x4_sad[2] + au2_4x4_sad[3]);
pi4_sad_grid[PART_ID_2NxnD_B] =
(au2_4x4_sad[15] + au2_4x4_sad[14] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_2Nx2N] =
pi4_sad_grid[PART_ID_2NxN_T] + pi4_sad_grid[PART_ID_2NxN_B];
pi4_sad_grid[PART_ID_2NxnU_B] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnU_T];
pi4_sad_grid[PART_ID_2NxnD_T] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnD_B];
pi4_sad_grid[PART_ID_nRx2N_L] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nRx2N_R];
pi4_sad_grid[PART_ID_nLx2N_R] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nLx2N_L];
}
}
{
S32 i4_sad, i4_mv_cost, i4_tot_cost;
S32 best_node_cost;
S32 second_best_node_cost;
ULWORD64 u8_temp_var, u8_temp_var1;
ULWORD64 u8_ref_X_Square, u8_pure_dist, u8_src_var, u8_ref_var;
{
S16 mvdx1, mvdy1;
S32 i4_search_idx = (S32)ps_result_prms->i1_ref_idx;
search_results_t *ps_search_results = ps_result_prms->ps_search_results;
S32 pred_lx = i4_search_idx;
pred_ctxt_t *ps_pred_ctxt = &ps_search_results->as_pred_ctxt[pred_lx];
pred_candt_nodes_t *ps_pred_nodes = &ps_pred_ctxt->as_pred_nodes[PART_2Nx2N];
search_node_t *ps_pred_node_a = ps_pred_nodes->ps_mvp_node;
S32 inp_shift = 2;
S32 pred_shift = ps_pred_node_a->u1_subpel_done ? 0 : 2;
S32 lambda_q_shift = ps_pred_ctxt->lambda_q_shift;
S32 lambda = ps_pred_ctxt->lambda;
S32 rnd = 1 << (lambda_q_shift - 1);
S32 mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
S32 mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
S32 ref_bits =
ps_pred_ctxt
->ppu1_ref_bits_tlu[ps_pred_ctxt->pred_lx][ps_search_node->i1_ref_idx];
COMPUTE_DIFF_MV(
mvdx1, mvdy1, ps_search_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
i4_mv_cost = hme_get_range(mvdx1) + hme_get_range(mvdy1) + (mvdx1 > 0) +
(mvdy1 > 0) + ref_bits + 2;
i4_mv_cost *= lambda;
i4_mv_cost += rnd;
i4_mv_cost >>= lambda_q_shift;
i4_mv_cost = CLIP_U16(i4_mv_cost);
}
for(i4_count = 0; i4_count < ps_mv_refine_ctxt->i4_num_valid_parts; i4_count++)
{
S32 i4_stim_injected_sad;
S32 i4_stim_injected_cost;
S32 i4_noise_term;
unsigned long u4_shift_val;
S32 i4_bits_req;
S32 update_required = 0;
S32 part_id = pi4_valid_part_ids[i4_count];
S32 index = (ps_mv_refine_ctxt->i4_num_valid_parts > 8) ? part_id : i4_count;
WORD32 i4_q_level = STIM_Q_FORMAT + ALPHA_Q_FORMAT;
S32 i4_inv_wt = ps_wt_inp_prms->a_inv_wpred_wt[ps_search_node->i1_ref_idx];
if(ps_search_prms->i4_alpha_stim_multiplier)
{
/* Compute ref sigmaX and sigmaX_Squared values for valid partitions from previously computed ref 4x4 level values */
hme_compute_final_sigma_of_pu_from_base_blocks(
au4_4x4_ref_sigmaX,
au4_4x4_ref_sigmaXSquared,
au8_final_ref_sigmaX,
au8_final_ref_sigmaXSquared,
16,
4,
part_id,
4);
u8_ref_X_Square =
(au8_final_ref_sigmaX[part_id] * au8_final_ref_sigmaX[part_id]);
u8_ref_var = (au8_final_ref_sigmaXSquared[part_id] - u8_ref_X_Square);
/* Multiply un-normalized src_var with inv_wt if its not same as default wt */
/* and shift the resulting src_var if its more than 27 bits to avoid overflow */
/* The amount by which it is shifted is passed on to u4_shift_val and applied equally on ref_var */
u4_shift_val = ihevce_calc_stim_injected_variance(
au8_final_src_sigmaX,
au8_final_src_sigmaXSquared,
&u8_src_var,
i4_inv_wt,
ps_wt_inp_prms->ai4_shift_val[ps_search_node->i1_ref_idx],
ps_wt_inp_prms->wpred_log_wdc,
part_id);
u8_ref_var = u8_ref_var >> u4_shift_val;
/* Do the same check on ref_var to avoid overflow and apply similar shift on src_var */
GETRANGE64(i4_bits_req, u8_ref_var);
if(i4_bits_req > 27)
{
u8_ref_var = u8_ref_var >> (i4_bits_req - 27);
u8_src_var = u8_src_var >> (i4_bits_req - 27);
}
if(u8_src_var == u8_ref_var)
{
u8_temp_var = (1 << STIM_Q_FORMAT);
}
else
{
u8_temp_var = (2 * u8_src_var * u8_ref_var);
u8_temp_var = (u8_temp_var * (1 << STIM_Q_FORMAT));
u8_temp_var1 = (u8_src_var * u8_src_var) + (u8_ref_var * u8_ref_var);
u8_temp_var = (u8_temp_var + (u8_temp_var1 / 2));
u8_temp_var = (u8_temp_var / u8_temp_var1);
}
i4_noise_term = (UWORD32)u8_temp_var;
ASSERT(i4_noise_term >= 0);
i4_noise_term *= ps_search_prms->i4_alpha_stim_multiplier;
}
else
{
i4_noise_term = 0;
}
u8_pure_dist = pi4_sad_grid[part_id];
u8_pure_dist *= ((1 << (i4_q_level)) - (i4_noise_term));
u8_pure_dist += (1 << ((i4_q_level)-1));
i4_stim_injected_sad = (UWORD32)(u8_pure_dist >> (i4_q_level));
i4_sad = CLIP3(pi4_sad_grid[part_id], 0, 0x7fff);
i4_tot_cost = CLIP_S16(i4_sad + i4_mv_cost);
i4_stim_injected_sad = CLIP3(i4_stim_injected_sad, 0, 0x7fff);
i4_stim_injected_cost = CLIP_S16(i4_stim_injected_sad + i4_mv_cost);
best_node_cost = CLIP_S16(ps_mv_refine_ctxt->i2_stim_injected_cost[0][index]);
second_best_node_cost =
CLIP_S16(ps_mv_refine_ctxt->i2_stim_injected_cost[1][index]);
if(i4_stim_injected_cost < second_best_node_cost)
{
update_required = 2;
if(i4_stim_injected_cost < best_node_cost)
{
update_required = 1;
}
else if(i4_stim_injected_cost == best_node_cost)
{
update_required = 0;
}
if(update_required == 2)
{
ps_mv_refine_ctxt->i2_tot_cost[1][index] = i4_tot_cost;
ps_mv_refine_ctxt->i2_stim_injected_cost[1][index] = i4_stim_injected_cost;
ps_mv_refine_ctxt->i2_mv_cost[1][index] = i4_mv_cost;
ps_mv_refine_ctxt->i2_mv_x[1][index] = ps_search_node->s_mv.i2_mvx;
ps_mv_refine_ctxt->i2_mv_y[1][index] = ps_search_node->s_mv.i2_mvy;
ps_mv_refine_ctxt->i2_ref_idx[1][index] = ps_search_node->i1_ref_idx;
}
else if(update_required == 1)
{
ps_mv_refine_ctxt->i2_tot_cost[1][index] =
ps_mv_refine_ctxt->i2_tot_cost[0][index];
ps_mv_refine_ctxt->i2_stim_injected_cost[1][index] =
ps_mv_refine_ctxt->i2_stim_injected_cost[0][index];
ps_mv_refine_ctxt->i2_mv_cost[1][index] =
ps_mv_refine_ctxt->i2_mv_cost[0][index];
ps_mv_refine_ctxt->i2_mv_x[1][index] = ps_mv_refine_ctxt->i2_mv_x[0][index];
ps_mv_refine_ctxt->i2_mv_y[1][index] = ps_mv_refine_ctxt->i2_mv_y[0][index];
ps_mv_refine_ctxt->i2_ref_idx[1][index] =
ps_mv_refine_ctxt->i2_ref_idx[0][index];
ps_mv_refine_ctxt->i2_tot_cost[0][index] = i4_tot_cost;
ps_mv_refine_ctxt->i2_stim_injected_cost[0][index] = i4_stim_injected_cost;
ps_mv_refine_ctxt->i2_mv_cost[0][index] = i4_mv_cost;
ps_mv_refine_ctxt->i2_mv_x[0][index] = ps_search_node->s_mv.i2_mvx;
ps_mv_refine_ctxt->i2_mv_y[0][index] = ps_search_node->s_mv.i2_mvy;
ps_mv_refine_ctxt->i2_ref_idx[0][index] = ps_search_node->i1_ref_idx;
}
}
}
}
ps_search_node++;
}
{
WORD32 i4_i;
WORD32 part_id;
search_node_t *ps_search_node = ps_search_prms->ps_search_nodes;
for(i4_i = 0; i4_i < ps_mv_refine_ctxt->i4_num_valid_parts; i4_i++)
{
part_id = ps_mv_refine_ctxt->ai4_part_id[i4_i];
if(ps_mv_refine_ctxt->i2_stim_injected_cost[0][part_id] >= MAX_SIGNED_16BIT_VAL)
{
ASSERT(ps_mv_refine_ctxt->i2_mv_cost[0][part_id] == MAX_SIGNED_16BIT_VAL);
ASSERT(ps_mv_refine_ctxt->i2_mv_x[0][part_id] == 0);
ASSERT(ps_mv_refine_ctxt->i2_mv_y[0][part_id] == 0);
ps_mv_refine_ctxt->i2_ref_idx[0][part_id] = ps_search_node->i1_ref_idx;
}
if(ps_mv_refine_ctxt->i2_stim_injected_cost[1][part_id] >= MAX_SIGNED_16BIT_VAL)
{
ASSERT(ps_mv_refine_ctxt->i2_mv_cost[1][part_id] == MAX_SIGNED_16BIT_VAL);
ASSERT(ps_mv_refine_ctxt->i2_mv_x[1][part_id] == 0);
ASSERT(ps_mv_refine_ctxt->i2_mv_y[1][part_id] == 0);
ps_mv_refine_ctxt->i2_ref_idx[1][part_id] = ps_search_node->i1_ref_idx;
}
}
}
}
void hme_calc_sad_and_1_best_result(
hme_search_prms_t *ps_search_prms,
wgt_pred_ctxt_t *ps_wt_inp_prms,
err_prms_t *ps_err_prms,
result_upd_prms_t *ps_result_prms,
U08 **ppu1_ref,
S32 i4_ref_stride)
{
S32 i4_candt;
S32 i4_inp_off;
S32 i4_ref_offset;
S32 i4_num_nodes;
S32 *pi4_sad_grid = ps_err_prms->pi4_sad_grid;
S32 cur_buf_stride = ps_err_prms->i4_inp_stride;
WORD32 ref_buf_stride = ps_err_prms->i4_ref_stride;
WORD32 cur_buf_stride_ls2 = (cur_buf_stride << 2);
WORD32 ref_buf_stride_ls2 = (ref_buf_stride << 2);
mv_refine_ctxt_t *ps_mv_refine_ctxt;
search_node_t *ps_search_node;
ps_mv_refine_ctxt = ps_search_prms->ps_fullpel_refine_ctxt;
i4_num_nodes = ps_search_prms->i4_num_search_nodes;
i4_inp_off = ps_search_prms->i4_cu_x_off;
i4_inp_off += ps_search_prms->i4_cu_y_off * cur_buf_stride;
i4_ref_offset = (i4_ref_stride * ps_search_prms->i4_y_off) + ps_search_prms->i4_x_off;
ps_search_node = ps_search_prms->ps_search_nodes;
for(i4_candt = 0; i4_candt < i4_num_nodes; i4_candt++)
{
/**********************************************************************/
/* CALL THE FUNCTION THAT COMPUTES THE SAD AND UPDATES THE SAD GRID */
/**********************************************************************/
{
WORD32 b, c, d;
UWORD8 *pu1_cur_ptr;
UWORD8 *pu1_ref_ptr;
UWORD16 au2_4x4_sad[NUM_4X4];
if(ps_search_node->s_mv.i2_mvx == INTRA_MV)
{
continue;
}
ps_err_prms->pu1_inp =
ps_wt_inp_prms->apu1_wt_inp[ps_search_node->i1_ref_idx] + i4_inp_off;
ps_err_prms->pu1_ref = ppu1_ref[ps_search_node->i1_ref_idx] + i4_ref_offset;
ps_err_prms->pu1_ref += ps_search_node->s_mv.i2_mvx;
ps_err_prms->pu1_ref += (ps_search_node->s_mv.i2_mvy * i4_ref_stride);
pu1_cur_ptr = ps_err_prms->pu1_inp;
pu1_ref_ptr = &ps_err_prms->pu1_ref[0];
/* Loop to compute the SAD's */
{
memset(&au2_4x4_sad[0], 0, NUM_4X4 * sizeof(UWORD16));
for(b = 0; b < NUM_4X4; b++)
{
WORD32 t1 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * cur_buf_stride_ls2;
WORD32 t2 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * ref_buf_stride_ls2;
for(c = 0; c < NUM_ROWS_IN_4X4; c++)
{
WORD32 z_cur = (cur_buf_stride)*c + t1;
WORD32 z_ref = (ref_buf_stride)*c + t2;
for(d = 0; d < NUM_PIXELS_IN_ROW; d++)
{
au2_4x4_sad[b] += (UWORD16)ABS((
((S32)pu1_ref_ptr[(z_ref + d)]) - ((S32)pu1_cur_ptr[(z_cur + d)])));
}
}
}
pi4_sad_grid[PART_ID_NxN_TL] =
(au2_4x4_sad[0] + au2_4x4_sad[1] + au2_4x4_sad[4] + au2_4x4_sad[5]);
pi4_sad_grid[PART_ID_NxN_TR] =
(au2_4x4_sad[2] + au2_4x4_sad[3] + au2_4x4_sad[6] + au2_4x4_sad[7]);
pi4_sad_grid[PART_ID_NxN_BL] =
(au2_4x4_sad[8] + au2_4x4_sad[9] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_NxN_BR] =
(au2_4x4_sad[10] + au2_4x4_sad[11] + au2_4x4_sad[14] + au2_4x4_sad[15]);
pi4_sad_grid[PART_ID_Nx2N_L] =
pi4_sad_grid[PART_ID_NxN_TL] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_Nx2N_R] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_BR];
pi4_sad_grid[PART_ID_2NxN_T] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_TL];
pi4_sad_grid[PART_ID_2NxN_B] =
pi4_sad_grid[PART_ID_NxN_BR] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_nLx2N_L] =
(au2_4x4_sad[8] + au2_4x4_sad[0] + au2_4x4_sad[12] + au2_4x4_sad[4]);
pi4_sad_grid[PART_ID_nRx2N_R] =
(au2_4x4_sad[3] + au2_4x4_sad[7] + au2_4x4_sad[15] + au2_4x4_sad[11]);
pi4_sad_grid[PART_ID_2NxnU_T] =
(au2_4x4_sad[1] + au2_4x4_sad[0] + au2_4x4_sad[2] + au2_4x4_sad[3]);
pi4_sad_grid[PART_ID_2NxnD_B] =
(au2_4x4_sad[15] + au2_4x4_sad[14] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_2Nx2N] =
pi4_sad_grid[PART_ID_2NxN_T] + pi4_sad_grid[PART_ID_2NxN_B];
pi4_sad_grid[PART_ID_2NxnU_B] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnU_T];
pi4_sad_grid[PART_ID_2NxnD_T] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnD_B];
pi4_sad_grid[PART_ID_nRx2N_L] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nRx2N_R];
pi4_sad_grid[PART_ID_nLx2N_R] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nLx2N_L];
}
}
{
S32 i4_count = 0, i4_sad, i4_mv_cost, i4_tot_cost;
S32 *pi4_valid_part_ids = &ps_mv_refine_ctxt->ai4_part_id[0];
S32 best_node_cost;
S32 second_best_node_cost;
{
S16 mvdx1, mvdy1;
S32 i4_search_idx = (S32)ps_result_prms->i1_ref_idx;
search_results_t *ps_search_results = ps_result_prms->ps_search_results;
S32 pred_lx = i4_search_idx;
pred_ctxt_t *ps_pred_ctxt = &ps_search_results->as_pred_ctxt[pred_lx];
pred_candt_nodes_t *ps_pred_nodes = &ps_pred_ctxt->as_pred_nodes[PART_2Nx2N];
search_node_t *ps_pred_node_a = ps_pred_nodes->ps_mvp_node;
S32 inp_shift = 2;
S32 pred_shift = ps_pred_node_a->u1_subpel_done ? 0 : 2;
S32 lambda_q_shift = ps_pred_ctxt->lambda_q_shift;
S32 lambda = ps_pred_ctxt->lambda;
S32 rnd = 1 << (lambda_q_shift - 1);
S32 mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
S32 mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
S32 ref_bits =
ps_pred_ctxt
->ppu1_ref_bits_tlu[ps_pred_ctxt->pred_lx][ps_search_node->i1_ref_idx];
COMPUTE_DIFF_MV(
mvdx1, mvdy1, ps_search_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
i4_mv_cost = hme_get_range(mvdx1) + hme_get_range(mvdy1) + (mvdx1 > 0) +
(mvdy1 > 0) + ref_bits + 2;
i4_mv_cost *= lambda;
i4_mv_cost += rnd;
i4_mv_cost >>= lambda_q_shift;
i4_mv_cost = CLIP_U16(i4_mv_cost);
}
/*For each valid partition, update the refine_prm structure to reflect the best and second
best candidates for that partition*/
for(i4_count = 0; i4_count < ps_mv_refine_ctxt->i4_num_valid_parts; i4_count++)
{
S32 update_required = 0;
S32 part_id = pi4_valid_part_ids[i4_count];
S32 index = (ps_mv_refine_ctxt->i4_num_valid_parts > 8) ? part_id : i4_count;
/*Calculate total cost*/
i4_sad = CLIP3(pi4_sad_grid[part_id], 0, 0x7fff);
i4_tot_cost = CLIP_S16(i4_sad + i4_mv_cost);
/*****************************************************************/
/* We do not labor through the results if the total cost worse */
/* than the last of the results. */
/*****************************************************************/
best_node_cost = CLIP_S16(ps_mv_refine_ctxt->i2_tot_cost[0][index]);
second_best_node_cost = SHRT_MAX;
if(i4_tot_cost < second_best_node_cost)
{
update_required = 0;
/*************************************************************/
/* Identify where the current result isto be placed.Basically*/
/* find the node which has cost just higher thannodeundertest*/
/*************************************************************/
if(i4_tot_cost < best_node_cost)
{
update_required = 1;
}
else if(i4_tot_cost == best_node_cost)
{
update_required = 0;
}
if(update_required == 2)
{
ps_mv_refine_ctxt->i2_tot_cost[1][index] = i4_tot_cost;
ps_mv_refine_ctxt->i2_mv_cost[1][index] = i4_mv_cost;
ps_mv_refine_ctxt->i2_mv_x[1][index] = ps_search_node->s_mv.i2_mvx;
ps_mv_refine_ctxt->i2_mv_y[1][index] = ps_search_node->s_mv.i2_mvy;
ps_mv_refine_ctxt->i2_ref_idx[1][index] = ps_search_node->i1_ref_idx;
}
else if(update_required == 1)
{
ps_mv_refine_ctxt->i2_tot_cost[0][index] = i4_tot_cost;
ps_mv_refine_ctxt->i2_mv_cost[0][index] = i4_mv_cost;
ps_mv_refine_ctxt->i2_mv_x[0][index] = ps_search_node->s_mv.i2_mvx;
ps_mv_refine_ctxt->i2_mv_y[0][index] = ps_search_node->s_mv.i2_mvy;
ps_mv_refine_ctxt->i2_ref_idx[0][index] = ps_search_node->i1_ref_idx;
}
}
}
}
ps_search_node++;
}
{
WORD32 i4_i;
WORD32 part_id;
search_node_t *ps_search_node = ps_search_prms->ps_search_nodes;
for(i4_i = 0; i4_i < ps_mv_refine_ctxt->i4_num_valid_parts; i4_i++)
{
part_id = ps_mv_refine_ctxt->ai4_part_id[i4_i];
if(ps_mv_refine_ctxt->i2_tot_cost[0][part_id] >= MAX_SIGNED_16BIT_VAL)
{
ASSERT(ps_mv_refine_ctxt->i2_mv_cost[0][part_id] == MAX_SIGNED_16BIT_VAL);
ASSERT(ps_mv_refine_ctxt->i2_mv_x[0][part_id] == 0);
ASSERT(ps_mv_refine_ctxt->i2_mv_y[0][part_id] == 0);
ps_mv_refine_ctxt->i2_ref_idx[0][part_id] = ps_search_node->i1_ref_idx;
}
}
}
}
void hme_calc_stim_injected_sad_and_1_best_result(
hme_search_prms_t *ps_search_prms,
wgt_pred_ctxt_t *ps_wt_inp_prms,
err_prms_t *ps_err_prms,
result_upd_prms_t *ps_result_prms,
U08 **ppu1_ref,
S32 i4_ref_stride)
{
mv_refine_ctxt_t *ps_mv_refine_ctxt;
search_node_t *ps_search_node;
S32 i4_candt;
S32 i4_count;
S32 i4_inp_off;
S32 i4_ref_offset;
S32 i4_num_nodes;
ULWORD64 *au8_final_src_sigmaX, *au8_final_src_sigmaXSquared, au8_final_ref_sigmaX[17],
au8_final_ref_sigmaXSquared[17];
UWORD32 au4_4x4_ref_sigmaX[NUM_4X4], au4_4x4_ref_sigmaXSquared[NUM_4X4];
S32 *pi4_valid_part_ids;
S32 *pi4_sad_grid = ps_err_prms->pi4_sad_grid;
S32 cur_buf_stride = ps_err_prms->i4_inp_stride;
WORD32 ref_buf_stride = ps_err_prms->i4_ref_stride;
WORD32 cur_buf_stride_ls2 = (cur_buf_stride << 2);
WORD32 ref_buf_stride_ls2 = (ref_buf_stride << 2);
ps_mv_refine_ctxt = ps_search_prms->ps_fullpel_refine_ctxt;
i4_num_nodes = ps_search_prms->i4_num_search_nodes;
i4_inp_off = ps_search_prms->i4_cu_x_off;
i4_inp_off += ps_search_prms->i4_cu_y_off * cur_buf_stride;
i4_ref_offset = (i4_ref_stride * ps_search_prms->i4_y_off) + ps_search_prms->i4_x_off;
ps_search_node = ps_search_prms->ps_search_nodes;
pi4_valid_part_ids = &ps_mv_refine_ctxt->ai4_part_id[0];
/* Set local pointer to point to partition level sigma values calculated in hme_refine */
au8_final_src_sigmaX = ps_search_prms->pu8_part_src_sigmaX;
au8_final_src_sigmaXSquared = ps_search_prms->pu8_part_src_sigmaXSquared;
for(i4_candt = 0; i4_candt < i4_num_nodes; i4_candt++)
{
{
WORD32 b, c, d;
UWORD8 *pu1_cur_ptr;
UWORD8 *pu1_ref_ptr;
UWORD16 au2_4x4_sad[NUM_4X4];
if(ps_search_node->s_mv.i2_mvx == INTRA_MV)
{
continue;
}
ps_err_prms->pu1_inp =
ps_wt_inp_prms->apu1_wt_inp[ps_search_node->i1_ref_idx] + i4_inp_off;
ps_err_prms->pu1_ref = ppu1_ref[ps_search_node->i1_ref_idx] + i4_ref_offset;
ps_err_prms->pu1_ref += ps_search_node->s_mv.i2_mvx;
ps_err_prms->pu1_ref += (ps_search_node->s_mv.i2_mvy * i4_ref_stride);
pu1_cur_ptr = ps_err_prms->pu1_inp;
pu1_ref_ptr = &ps_err_prms->pu1_ref[0];
/* Loop to compute the SAD's */
{
memset(&au2_4x4_sad[0], 0, NUM_4X4 * sizeof(UWORD16));
for(b = 0; b < NUM_4X4; b++)
{
WORD32 t1 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * cur_buf_stride_ls2;
WORD32 t2 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * ref_buf_stride_ls2;
for(c = 0; c < NUM_ROWS_IN_4X4; c++)
{
WORD32 z_cur = (cur_buf_stride)*c + t1;
WORD32 z_ref = (ref_buf_stride)*c + t2;
for(d = 0; d < NUM_PIXELS_IN_ROW; d++)
{
au2_4x4_sad[b] += (UWORD16)ABS((
((S32)pu1_ref_ptr[(z_ref + d)]) - ((S32)pu1_cur_ptr[(z_cur + d)])));
}
}
}
/* Compute sigmaX and sigmaX_Squared at 4x4 level for ref from ref_ptr */
hme_compute_sigmaX_and_sigmaXSquared(
pu1_ref_ptr,
ref_buf_stride,
au4_4x4_ref_sigmaX,
au4_4x4_ref_sigmaXSquared,
4,
4,
16,
16,
1,
4);
pi4_sad_grid[PART_ID_NxN_TL] =
(au2_4x4_sad[0] + au2_4x4_sad[1] + au2_4x4_sad[4] + au2_4x4_sad[5]);
pi4_sad_grid[PART_ID_NxN_TR] =
(au2_4x4_sad[2] + au2_4x4_sad[3] + au2_4x4_sad[6] + au2_4x4_sad[7]);
pi4_sad_grid[PART_ID_NxN_BL] =
(au2_4x4_sad[8] + au2_4x4_sad[9] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_NxN_BR] =
(au2_4x4_sad[10] + au2_4x4_sad[11] + au2_4x4_sad[14] + au2_4x4_sad[15]);
pi4_sad_grid[PART_ID_Nx2N_L] =
pi4_sad_grid[PART_ID_NxN_TL] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_Nx2N_R] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_BR];
pi4_sad_grid[PART_ID_2NxN_T] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_TL];
pi4_sad_grid[PART_ID_2NxN_B] =
pi4_sad_grid[PART_ID_NxN_BR] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_nLx2N_L] =
(au2_4x4_sad[8] + au2_4x4_sad[0] + au2_4x4_sad[12] + au2_4x4_sad[4]);
pi4_sad_grid[PART_ID_nRx2N_R] =
(au2_4x4_sad[3] + au2_4x4_sad[7] + au2_4x4_sad[15] + au2_4x4_sad[11]);
pi4_sad_grid[PART_ID_2NxnU_T] =
(au2_4x4_sad[1] + au2_4x4_sad[0] + au2_4x4_sad[2] + au2_4x4_sad[3]);
pi4_sad_grid[PART_ID_2NxnD_B] =
(au2_4x4_sad[15] + au2_4x4_sad[14] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_2Nx2N] =
pi4_sad_grid[PART_ID_2NxN_T] + pi4_sad_grid[PART_ID_2NxN_B];
pi4_sad_grid[PART_ID_2NxnU_B] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnU_T];
pi4_sad_grid[PART_ID_2NxnD_T] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnD_B];
pi4_sad_grid[PART_ID_nRx2N_L] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nRx2N_R];
pi4_sad_grid[PART_ID_nLx2N_R] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nLx2N_L];
}
}
{
S32 i4_sad, i4_mv_cost, i4_tot_cost;
S32 best_node_cost;
S32 second_best_node_cost;
ULWORD64 u8_temp_var, u8_temp_var1;
ULWORD64 u8_ref_X_Square, u8_pure_dist, u8_src_var, u8_ref_var;
{
S16 mvdx1, mvdy1;
S32 i4_search_idx = (S32)ps_result_prms->i1_ref_idx;
search_results_t *ps_search_results = ps_result_prms->ps_search_results;
S32 pred_lx = i4_search_idx;
pred_ctxt_t *ps_pred_ctxt = &ps_search_results->as_pred_ctxt[pred_lx];
pred_candt_nodes_t *ps_pred_nodes = &ps_pred_ctxt->as_pred_nodes[PART_2Nx2N];
search_node_t *ps_pred_node_a = ps_pred_nodes->ps_mvp_node;
S32 inp_shift = 2;
S32 pred_shift = ps_pred_node_a->u1_subpel_done ? 0 : 2;
S32 lambda_q_shift = ps_pred_ctxt->lambda_q_shift;
S32 lambda = ps_pred_ctxt->lambda;
S32 rnd = 1 << (lambda_q_shift - 1);
S32 mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
S32 mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
S32 ref_bits =
ps_pred_ctxt
->ppu1_ref_bits_tlu[ps_pred_ctxt->pred_lx][ps_search_node->i1_ref_idx];
COMPUTE_DIFF_MV(
mvdx1, mvdy1, ps_search_node, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
i4_mv_cost = hme_get_range(mvdx1) + hme_get_range(mvdy1) + (mvdx1 > 0) +
(mvdy1 > 0) + ref_bits + 2;
i4_mv_cost *= lambda;
i4_mv_cost += rnd;
i4_mv_cost >>= lambda_q_shift;
i4_mv_cost = CLIP_U16(i4_mv_cost);
}
for(i4_count = 0; i4_count < ps_mv_refine_ctxt->i4_num_valid_parts; i4_count++)
{
S32 i4_stim_injected_sad;
S32 i4_stim_injected_cost;
S32 i4_noise_term;
unsigned long u4_shift_val;
S32 i4_bits_req;
S32 update_required = 0;
S32 part_id = pi4_valid_part_ids[i4_count];
S32 index = (ps_mv_refine_ctxt->i4_num_valid_parts > 8) ? part_id : i4_count;
WORD32 i4_q_level = STIM_Q_FORMAT + ALPHA_Q_FORMAT;
S32 i4_inv_wt = ps_wt_inp_prms->a_inv_wpred_wt[ps_search_node->i1_ref_idx];
if(ps_search_prms->i4_alpha_stim_multiplier)
{
/* Compute ref sigmaX and sigmaX_Squared values for valid partitions from previously computed ref 4x4 level values */
hme_compute_final_sigma_of_pu_from_base_blocks(
au4_4x4_ref_sigmaX,
au4_4x4_ref_sigmaXSquared,
au8_final_ref_sigmaX,
au8_final_ref_sigmaXSquared,
16,
4,
part_id,
4);
u8_ref_X_Square =
(au8_final_ref_sigmaX[part_id] * au8_final_ref_sigmaX[part_id]);
u8_ref_var = (au8_final_ref_sigmaXSquared[part_id] - u8_ref_X_Square);
/* Multiply un-normalized src_var with inv_wt if its not same as default wt */
/* and shift the resulting src_var if its more than 27 bits to avoid overflow */
/* The amount by which it is shifted is passed on to u4_shift_val and applied equally on ref_var */
u4_shift_val = ihevce_calc_stim_injected_variance(
au8_final_src_sigmaX,
au8_final_src_sigmaXSquared,
&u8_src_var,
i4_inv_wt,
ps_wt_inp_prms->ai4_shift_val[ps_search_node->i1_ref_idx],
ps_wt_inp_prms->wpred_log_wdc,
part_id);
u8_ref_var = u8_ref_var >> u4_shift_val;
/* Do the same check on ref_var to avoid overflow and apply similar shift on src_var */
GETRANGE64(i4_bits_req, u8_ref_var);
if(i4_bits_req > 27)
{
u8_ref_var = u8_ref_var >> (i4_bits_req - 27);
u8_src_var = u8_src_var >> (i4_bits_req - 27);
}
if(u8_src_var == u8_ref_var)
{
u8_temp_var = (1 << STIM_Q_FORMAT);
}
else
{
u8_temp_var = (2 * u8_src_var * u8_ref_var);
u8_temp_var = (u8_temp_var * (1 << STIM_Q_FORMAT));
u8_temp_var1 = (u8_src_var * u8_src_var) + (u8_ref_var * u8_ref_var);
u8_temp_var = (u8_temp_var + (u8_temp_var1 / 2));
u8_temp_var = (u8_temp_var / u8_temp_var1);
}
i4_noise_term = (UWORD32)u8_temp_var;
ASSERT(i4_noise_term >= 0);
i4_noise_term *= ps_search_prms->i4_alpha_stim_multiplier;
}
else
{
i4_noise_term = 0;
}
u8_pure_dist = pi4_sad_grid[part_id];
u8_pure_dist *= ((1 << (i4_q_level)) - (i4_noise_term));
u8_pure_dist += (1 << ((i4_q_level)-1));
i4_stim_injected_sad = (UWORD32)(u8_pure_dist >> (i4_q_level));
i4_sad = CLIP3(pi4_sad_grid[part_id], 0, 0x7fff);
i4_tot_cost = CLIP_S16(i4_sad + i4_mv_cost);
i4_stim_injected_sad = CLIP3(i4_stim_injected_sad, 0, 0x7fff);
i4_stim_injected_cost = CLIP_S16(i4_stim_injected_sad + i4_mv_cost);
best_node_cost = CLIP_S16(ps_mv_refine_ctxt->i2_stim_injected_cost[0][index]);
second_best_node_cost = SHRT_MAX;
if(i4_stim_injected_cost < second_best_node_cost)
{
update_required = 0;
if(i4_stim_injected_cost < best_node_cost)
{
update_required = 1;
}
else if(i4_stim_injected_cost == best_node_cost)
{
update_required = 0;
}
if(update_required == 2)
{
ps_mv_refine_ctxt->i2_tot_cost[1][index] = i4_tot_cost;
ps_mv_refine_ctxt->i2_stim_injected_cost[1][index] = i4_stim_injected_cost;
ps_mv_refine_ctxt->i2_mv_cost[1][index] = i4_mv_cost;
ps_mv_refine_ctxt->i2_mv_x[1][index] = ps_search_node->s_mv.i2_mvx;
ps_mv_refine_ctxt->i2_mv_y[1][index] = ps_search_node->s_mv.i2_mvy;
ps_mv_refine_ctxt->i2_ref_idx[1][index] = ps_search_node->i1_ref_idx;
}
else if(update_required == 1)
{
ps_mv_refine_ctxt->i2_tot_cost[0][index] = i4_tot_cost;
ps_mv_refine_ctxt->i2_stim_injected_cost[0][index] = i4_stim_injected_cost;
ps_mv_refine_ctxt->i2_mv_cost[0][index] = i4_mv_cost;
ps_mv_refine_ctxt->i2_mv_x[0][index] = ps_search_node->s_mv.i2_mvx;
ps_mv_refine_ctxt->i2_mv_y[0][index] = ps_search_node->s_mv.i2_mvy;
ps_mv_refine_ctxt->i2_ref_idx[0][index] = ps_search_node->i1_ref_idx;
}
}
}
}
ps_search_node++;
}
{
WORD32 i4_i;
WORD32 part_id;
search_node_t *ps_search_node = ps_search_prms->ps_search_nodes;
for(i4_i = 0; i4_i < ps_mv_refine_ctxt->i4_num_valid_parts; i4_i++)
{
part_id = ps_mv_refine_ctxt->ai4_part_id[i4_i];
if(ps_mv_refine_ctxt->i2_stim_injected_cost[0][part_id] >= MAX_SIGNED_16BIT_VAL)
{
ASSERT(ps_mv_refine_ctxt->i2_mv_cost[0][part_id] == MAX_SIGNED_16BIT_VAL);
ASSERT(ps_mv_refine_ctxt->i2_mv_x[0][part_id] == 0);
ASSERT(ps_mv_refine_ctxt->i2_mv_y[0][part_id] == 0);
ps_mv_refine_ctxt->i2_ref_idx[0][part_id] = ps_search_node->i1_ref_idx;
}
}
}
}
void hme_calc_sad_and_1_best_result_subpel(
err_prms_t *ps_err_prms, result_upd_prms_t *ps_result_prms)
{
S32 i4_candt;
S32 i4_num_nodes;
S32 *pi4_sad_grid = ps_err_prms->pi4_sad_grid;
S32 cur_buf_stride = ps_err_prms->i4_inp_stride;
WORD32 ref_buf_stride = ps_err_prms->i4_ref_stride;
WORD32 cur_buf_stride_ls2 = (cur_buf_stride << 2);
WORD32 ref_buf_stride_ls2 = (ref_buf_stride << 2);
mv_refine_ctxt_t *ps_subpel_refine_ctxt;
ps_subpel_refine_ctxt = ps_result_prms->ps_subpel_refine_ctxt;
i4_num_nodes = 1;
/* Run through each of the candts in a loop */
for(i4_candt = 0; i4_candt < i4_num_nodes; i4_candt++)
{
/**********************************************************************/
/* CALL THE FUNCTION THAT COMPUTES THE SAD AND UPDATES THE SAD GRID */
/**********************************************************************/
{
WORD32 b, c, d;
UWORD8 *pu1_cur_ptr;
UWORD8 *pu1_ref_ptr;
UWORD16 au2_4x4_sad[NUM_4X4];
pu1_cur_ptr = ps_err_prms->pu1_inp;
pu1_ref_ptr = &ps_err_prms->pu1_ref[0];
/* Loop to compute the SAD's */
{
memset(&au2_4x4_sad[0], 0, NUM_4X4 * sizeof(UWORD16));
for(b = 0; b < NUM_4X4; b++)
{
WORD32 t1 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * cur_buf_stride_ls2;
WORD32 t2 = (b % 4) * NUM_PIXELS_IN_ROW + (b >> 2) * ref_buf_stride_ls2;
for(c = 0; c < NUM_ROWS_IN_4X4; c++)
{
WORD32 z_cur = (cur_buf_stride)*c + t1;
WORD32 z_ref = (ref_buf_stride)*c + t2;
for(d = 0; d < NUM_PIXELS_IN_ROW; d++)
{
au2_4x4_sad[b] += (UWORD16)ABS((
((S32)pu1_ref_ptr[(z_ref + d)]) - ((S32)pu1_cur_ptr[(z_cur + d)])));
}
}
}
pi4_sad_grid[PART_ID_NxN_TL] =
(au2_4x4_sad[0] + au2_4x4_sad[1] + au2_4x4_sad[4] + au2_4x4_sad[5]);
pi4_sad_grid[PART_ID_NxN_TR] =
(au2_4x4_sad[2] + au2_4x4_sad[3] + au2_4x4_sad[6] + au2_4x4_sad[7]);
pi4_sad_grid[PART_ID_NxN_BL] =
(au2_4x4_sad[8] + au2_4x4_sad[9] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_NxN_BR] =
(au2_4x4_sad[10] + au2_4x4_sad[11] + au2_4x4_sad[14] + au2_4x4_sad[15]);
pi4_sad_grid[PART_ID_Nx2N_L] =
pi4_sad_grid[PART_ID_NxN_TL] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_Nx2N_R] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_BR];
pi4_sad_grid[PART_ID_2NxN_T] =
pi4_sad_grid[PART_ID_NxN_TR] + pi4_sad_grid[PART_ID_NxN_TL];
pi4_sad_grid[PART_ID_2NxN_B] =
pi4_sad_grid[PART_ID_NxN_BR] + pi4_sad_grid[PART_ID_NxN_BL];
pi4_sad_grid[PART_ID_nLx2N_L] =
(au2_4x4_sad[8] + au2_4x4_sad[0] + au2_4x4_sad[12] + au2_4x4_sad[4]);
pi4_sad_grid[PART_ID_nRx2N_R] =
(au2_4x4_sad[3] + au2_4x4_sad[7] + au2_4x4_sad[15] + au2_4x4_sad[11]);
pi4_sad_grid[PART_ID_2NxnU_T] =
(au2_4x4_sad[1] + au2_4x4_sad[0] + au2_4x4_sad[2] + au2_4x4_sad[3]);
pi4_sad_grid[PART_ID_2NxnD_B] =
(au2_4x4_sad[15] + au2_4x4_sad[14] + au2_4x4_sad[12] + au2_4x4_sad[13]);
pi4_sad_grid[PART_ID_2Nx2N] =
pi4_sad_grid[PART_ID_2NxN_T] + pi4_sad_grid[PART_ID_2NxN_B];
pi4_sad_grid[PART_ID_2NxnU_B] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnU_T];
pi4_sad_grid[PART_ID_2NxnD_T] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_2NxnD_B];
pi4_sad_grid[PART_ID_nRx2N_L] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nRx2N_R];
pi4_sad_grid[PART_ID_nLx2N_R] =
pi4_sad_grid[PART_ID_2Nx2N] - pi4_sad_grid[PART_ID_nLx2N_L];
}
}
/**********************************************************************/
/* CALL THE FUNCTION THAT COMPUTES UPDATES THE BEST RESULTS */
/**********************************************************************/
{
S32 i4_count = 0, i4_sad, i4_mv_cost, i4_tot_cost;
S32 *pi4_valid_part_ids = &ps_subpel_refine_ctxt->ai4_part_id[0];
S32 best_node_cost;
S32 second_best_node_cost;
/*For each valid partition, update the refine_prm structure to reflect the best and second
best candidates for that partition*/
for(i4_count = 0; i4_count < ps_subpel_refine_ctxt->i4_num_valid_parts; i4_count++)
{
S32 update_required = 0;
S32 part_id = pi4_valid_part_ids[i4_count];
S32 index = (ps_subpel_refine_ctxt->i4_num_valid_parts > 8) ? part_id : i4_count;
/* Use a pre-computed cost instead of freshly evaluating subpel cost */
i4_mv_cost = ps_subpel_refine_ctxt->i2_mv_cost[0][index];
/*Calculate total cost*/
i4_sad = CLIP3(pi4_sad_grid[part_id], 0, 0x7fff);
i4_tot_cost = CLIP_S16(i4_sad + i4_mv_cost);
/*****************************************************************/
/* We do not labor through the results if the total cost worse */
/* than the last of the results. */
/*****************************************************************/
best_node_cost = CLIP_S16(ps_subpel_refine_ctxt->i2_tot_cost[0][index]);
second_best_node_cost = SHRT_MAX;
if(i4_tot_cost < second_best_node_cost)
{
update_required = 0;
/*************************************************************/
/* Identify where the current result isto be placed.Basically*/
/* find the node which has cost just higher thannodeundertest*/
/*************************************************************/
if(i4_tot_cost < best_node_cost)
{
update_required = 1;
}
else if(i4_tot_cost == ps_subpel_refine_ctxt->i2_tot_cost[0][index])
{
update_required = 0;
}
if(update_required == 2)
{
ps_subpel_refine_ctxt->i2_tot_cost[1][index] = i4_tot_cost;
ps_subpel_refine_ctxt->i2_mv_cost[1][index] = i4_mv_cost;
ps_subpel_refine_ctxt->i2_mv_x[1][index] = ps_result_prms->i2_mv_x;
ps_subpel_refine_ctxt->i2_mv_y[1][index] = ps_result_prms->i2_mv_y;
ps_subpel_refine_ctxt->i2_ref_idx[1][index] = ps_result_prms->i1_ref_idx;
}
else if(update_required == 1)
{
ps_subpel_refine_ctxt->i2_tot_cost[0][index] = i4_tot_cost;
ps_subpel_refine_ctxt->i2_mv_cost[0][index] = i4_mv_cost;
ps_subpel_refine_ctxt->i2_mv_x[0][index] = ps_result_prms->i2_mv_x;
ps_subpel_refine_ctxt->i2_mv_y[0][index] = ps_result_prms->i2_mv_y;
ps_subpel_refine_ctxt->i2_ref_idx[0][index] = ps_result_prms->i1_ref_idx;
}
}
}
}
}
{
WORD32 i4_count = 0;
for(i4_count = 0; i4_count < TOT_NUM_PARTS; i4_count++)
{
if(ps_subpel_refine_ctxt->i2_tot_cost[0][i4_count] >= MAX_SIGNED_16BIT_VAL)
{
ps_subpel_refine_ctxt->ai2_fullpel_satd[0][i4_count] = MAX_SIGNED_16BIT_VAL;
}
}
}
}
/**
********************************************************************************
* @fn hme_calc_pt_sad_and_result_explicit(hme_search_prms_t *ps_search_prms,
* wgt_pred_ctxt_t *ps_wt_inp_prms,
* err_prms_t *ps_err_prms,
* result_upd_prms_t *ps_result_prms,
* U08 **ppu1_ref,
* S32 i4_ref_stride)
*
* @brief Run thorugh the provided candidates and compute the point SAD and
* cost and update the results in the order
*
* @param[in] ps_search_prms
* @param[in] ps_wt_inp_prms
* @param[in] ps_err_prms
* @param[out] ps_result_prms
* @param[in] ppu1_ref
* @param[in] i4_ref_stride
*
* @return None
********************************************************************************
*/
void hme_calc_pt_sad_and_result_explicit(
hme_search_prms_t *ps_search_prms,
wgt_pred_ctxt_t *ps_wt_inp_prms,
err_prms_t *ps_err_prms,
result_upd_prms_t *ps_result_prms,
U08 **ppu1_ref,
S32 i4_ref_stride)
{
WORD32 i4_grid_mask, i4_part_mask, i4_num_results, i4_candt, i4_num_nodes;
WORD32 i4_inp_stride, i4_inp_off, i4_ref_offset;
search_node_t *ps_search_node;
BLK_SIZE_T e_blk_size;
PF_SAD_FXN_T pf_sad_fxn;
PF_RESULT_FXN_T pf_hme_result_fxn;
i4_grid_mask = 0x1; /* Point SAD */
/* Get the parameters required */
i4_part_mask = ps_search_prms->i4_part_mask;
e_blk_size = ps_search_prms->e_blk_size;
i4_num_results = (S32)ps_search_prms->ps_search_results->u1_num_results_per_part;
i4_num_nodes = ps_search_prms->i4_num_search_nodes;
ps_search_node = ps_search_prms->ps_search_nodes;
i4_inp_stride = ps_search_prms->i4_inp_stride;
/* Move to the location of the search blk in inp buffer */
i4_inp_off = ps_search_prms->i4_cu_x_off;
i4_inp_off += ps_search_prms->i4_cu_y_off * i4_inp_stride;
i4_ref_offset = (i4_ref_stride * ps_search_prms->i4_y_off) + ps_search_prms->i4_x_off;
pf_sad_fxn = hme_get_sad_fxn(e_blk_size, i4_grid_mask, i4_part_mask);
/**********************************************************************/
/* we have a sparsely populated SAD grid of size 9x17. */
/* the id of the results in the grid is shown */
/* 5 2 6 */
/* 1 0 3 */
/* 7 4 8 */
/* The motivation for choosing a grid like this is that */
/* in case of no refinement, the central location is */
/* the first entry in the grid */
/* Also for diamond, the 4 entries get considered first */
/* This is consistent with the diamond notation used in */
/* subpel refinement. To Check */
/* Update the results for the given search candt */
/* returns the cost of the 2Nx2N partition */
/**********************************************************************/
/* Get the modified update result fun. with CLIP16 of cost to match */
/* with SIMD */
pf_hme_result_fxn = hme_update_results_grid_pu_bestn_no_encode;
for(i4_candt = 0; i4_candt < i4_num_nodes; i4_candt++)
{
if(ps_search_node->s_mv.i2_mvx == INTRA_MV)
continue;
/* initialize minimum cost for this candidate. As we search around */
/* this candidate, this is used to check early exit, when in any */
/* given iteration, the center pt of the grid is lowest value */
ps_result_prms->i4_min_cost = MAX_32BIT_VAL;
ps_err_prms->pu1_inp = ps_wt_inp_prms->apu1_wt_inp[ps_search_node->i1_ref_idx] + i4_inp_off;
ps_err_prms->i4_grid_mask = i4_grid_mask;
ps_err_prms->pu1_ref = ppu1_ref[ps_search_node->i1_ref_idx] + i4_ref_offset;
ps_err_prms->pu1_ref += ps_search_node->s_mv.i2_mvx;
ps_err_prms->pu1_ref += (ps_search_node->s_mv.i2_mvy * i4_ref_stride);
/**********************************************************************/
/* CALL THE FUNCTION THAT COMPUTES THE SAD AND UPDATES THE SAD GRID */
/**********************************************************************/
pf_sad_fxn(ps_err_prms);
/**********************************************************************/
/* CALL THE FUNCTION THAT COMPUTES UPDATES THE BEST RESULTS */
/**********************************************************************/
ps_result_prms->i4_grid_mask = i4_grid_mask;
ps_result_prms->ps_search_node_base = ps_search_node;
pf_hme_result_fxn(ps_result_prms);
ps_search_node++;
}
}
/**
********************************************************************************
* @fn hme_set_mvp_node(search_results_t *ps_search_results,
* search_node_t *ps_candt_prj_coloc,
* S08 i1_ref_idx)
*
* @brief Set node used for motion vector predictor computation
* Either TR or L is compared to projected colocated and
* closest is decided as MVP
*
* @param[in] ps_search_results
*
* @param[in] ps_candt_prj_coloc
*
* @param[in] i1_ref_idx
*
* @return None
********************************************************************************
*/
void hme_set_mvp_node(
search_results_t *ps_search_results,
search_node_t *ps_candt_prj_coloc,
U08 u1_pred_lx,
U08 u1_default_ref_id)
{
S32 i;
pred_ctxt_t *ps_pred_ctxt = &ps_search_results->as_pred_ctxt[u1_pred_lx];
pred_candt_nodes_t *ps_pred_nodes = ps_pred_ctxt->as_pred_nodes;
search_node_t *ps_pred_node_a = NULL, *ps_pred_node_b = NULL;
S32 inp_shift = 2;
S32 pred_shift;
S32 ref_bits;
S32 mv_p_x, mv_p_y;
S16 mvdx1, mvdx2, mvdy1, mvdy2;
ref_bits = ps_pred_ctxt->ppu1_ref_bits_tlu[u1_pred_lx][u1_default_ref_id];
/*************************************************************************/
/* Priority to bottom left availability. Else we go to left. If both are */
/* not available, then a remains null */
/*************************************************************************/
if(ps_pred_nodes->ps_l->u1_is_avail)
{
ps_pred_node_a = ps_pred_nodes->ps_l;
}
if((!(ps_pred_ctxt->proj_used) && (ps_pred_nodes->ps_tr->u1_is_avail)))
{
ps_pred_node_b = ps_pred_nodes->ps_tr;
}
else
{
ps_pred_node_b = ps_pred_nodes->ps_coloc;
ps_pred_node_b->s_mv = ps_pred_node_b->ps_mv[0];
}
if(ps_pred_node_a == NULL)
{
ps_pred_node_a = ps_pred_nodes->ps_coloc;
ps_pred_node_a->s_mv = ps_pred_node_a->ps_mv[0];
if(ps_pred_node_b == ps_pred_nodes->ps_coloc)
{
ps_pred_node_b = ps_pred_nodes->ps_zeromv;
ps_pred_node_b->s_mv = ps_pred_node_b->ps_mv[0];
}
}
if(ps_pred_node_a->i1_ref_idx != u1_default_ref_id)
{
SCALE_FOR_POC_DELTA(
mv_p_x, mv_p_y, ps_pred_node_a, u1_default_ref_id, ps_pred_ctxt->pi2_ref_scf);
}
else
{
mv_p_x = ps_pred_node_a->s_mv.i2_mvx;
mv_p_y = ps_pred_node_a->s_mv.i2_mvy;
}
pred_shift = ps_pred_node_a->u1_subpel_done ? 0 : 2;
COMPUTE_MV_DIFFERENCE(mvdx1, mvdy1, ps_candt_prj_coloc, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx1 = ABS(mvdx1);
mvdy1 = ABS(mvdy1);
if(ps_pred_node_b->i1_ref_idx != u1_default_ref_id)
{
SCALE_FOR_POC_DELTA(
mv_p_x, mv_p_y, ps_pred_node_b, u1_default_ref_id, ps_pred_ctxt->pi2_ref_scf);
}
else
{
mv_p_x = ps_pred_node_b->s_mv.i2_mvx;
mv_p_y = ps_pred_node_b->s_mv.i2_mvy;
}
pred_shift = ps_pred_node_b->u1_subpel_done ? 0 : 2;
COMPUTE_MV_DIFFERENCE(mvdx2, mvdy2, ps_candt_prj_coloc, mv_p_x, mv_p_y, inp_shift, pred_shift);
mvdx2 = ABS(mvdx2);
mvdy2 = ABS(mvdy2);
if((mvdx1 + mvdy1) < (mvdx2 + mvdy2))
{
for(i = 0; i < TOT_NUM_PARTS; i++)
{
ps_pred_nodes[i].ps_mvp_node = ps_pred_node_a;
}
}
else
{
for(i = 0; i < TOT_NUM_PARTS; i++)
{
ps_pred_nodes[i].ps_mvp_node = ps_pred_node_b;
}
}
}