3784 lines
158 KiB
C
3784 lines
158 KiB
C
/******************************************************************************
|
|
*
|
|
* 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)
|
|
{
|
|
/*************************************************************/
|
|
/* 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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|