320 lines
13 KiB
C
320 lines
13 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 est_sad.c
|
|
*
|
|
* \brief
|
|
* This file contain sad estimation related functions
|
|
*
|
|
* \date
|
|
*
|
|
* \author
|
|
* ittiam
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
/*****************************************************************************/
|
|
/* File Includes */
|
|
/*****************************************************************************/
|
|
/* User include files */
|
|
#include "ittiam_datatypes.h"
|
|
#include "rc_common.h"
|
|
#include "rc_cntrl_param.h"
|
|
#include "var_q_operator.h"
|
|
#include "mem_req_and_acq.h"
|
|
#include "est_sad.h"
|
|
|
|
typedef struct est_sad_t
|
|
{
|
|
WORD32 i4_use_est_intra_sad;
|
|
UWORD32 au4_prev_frm_sad[MAX_PIC_TYPE]; /* Previous frame SAD */
|
|
UWORD32 u4_n_p_frm_ifi_avg_sad; /* Current (nth) ifi average P frame SAD */
|
|
UWORD32 u4_n_1_p_frm_ifi_avg_sad; /* (n-1)th ifi average P frame SAD */
|
|
UWORD32 u4_n_2_p_frm_ifi_avg_sad; /* (n-2)th ifi average P frame SAD */
|
|
WORD32 i4_num_ifi_encoded; /* number of ifi encoded till now */
|
|
WORD32 i4_num_p_frm_in_cur_ifi; /* number of P frames in the current IFI */
|
|
} est_sad_t;
|
|
|
|
#if NON_STEADSTATE_CODE
|
|
WORD32 est_sad_num_fill_use_free_memtab(
|
|
est_sad_t **pps_est_sad, itt_memtab_t *ps_memtab, ITT_FUNC_TYPE_E e_func_type)
|
|
{
|
|
WORD32 i4_mem_tab_idx = 0;
|
|
static est_sad_t s_est_sad;
|
|
|
|
/* Hack for al alloc, during which we dont have any state memory.
|
|
Dereferencing can cause issues */
|
|
if(e_func_type == GET_NUM_MEMTAB || e_func_type == FILL_MEMTAB)
|
|
(*pps_est_sad) = &s_est_sad;
|
|
|
|
/*for src rate control state structure*/
|
|
if(e_func_type != GET_NUM_MEMTAB)
|
|
{
|
|
fill_memtab(
|
|
&ps_memtab[i4_mem_tab_idx], sizeof(est_sad_t), MEM_TAB_ALIGNMENT, PERSISTENT, DDR);
|
|
use_or_fill_base(&ps_memtab[0], (void **)pps_est_sad, e_func_type);
|
|
}
|
|
i4_mem_tab_idx++;
|
|
|
|
return (i4_mem_tab_idx);
|
|
}
|
|
#endif /* #if NON_STEADSTATE_CODE */
|
|
/****************************************************************************
|
|
Function Name : init_est_sad
|
|
Description :
|
|
Inputs : ps_est_sad
|
|
i4_use_est_intra_sad
|
|
|
|
Revision History:
|
|
DD MM YYYY Author(s) Changes (Describe the changes made)
|
|
*****************************************************************************/
|
|
void init_est_sad(est_sad_t *ps_est_sad, WORD32 i4_use_est_intra_sad)
|
|
{
|
|
WORD32 i;
|
|
ps_est_sad->i4_use_est_intra_sad = i4_use_est_intra_sad;
|
|
|
|
for(i = 0; i < MAX_PIC_TYPE; i++)
|
|
ps_est_sad->au4_prev_frm_sad[i] = 0;
|
|
|
|
ps_est_sad->u4_n_p_frm_ifi_avg_sad = 0;
|
|
ps_est_sad->u4_n_1_p_frm_ifi_avg_sad = 0;
|
|
ps_est_sad->u4_n_2_p_frm_ifi_avg_sad = 0;
|
|
ps_est_sad->i4_num_ifi_encoded = 0;
|
|
ps_est_sad->i4_num_p_frm_in_cur_ifi = 0;
|
|
}
|
|
/****************************************************************************
|
|
Function Name : reset_est_sad
|
|
Description :
|
|
Inputs : ps_est_sad
|
|
|
|
Revision History:
|
|
DD MM YYYY Author(s) Changes (Describe the changes made)
|
|
*****************************************************************************/
|
|
void reset_est_sad(est_sad_t *ps_est_sad)
|
|
{
|
|
init_est_sad(ps_est_sad, ps_est_sad->i4_use_est_intra_sad);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Function Name : get_est_sad
|
|
Description :
|
|
Inputs : ps_est_sad
|
|
|
|
Revision History:
|
|
DD MM YYYY Author(s) Changes (Describe the changes made)
|
|
*****************************************************************************/
|
|
/*
|
|
Get estimated SAD can be called at any point. The various use cases are:
|
|
1) When a I frame is getting encoded,
|
|
- get the estimated of P => No issues since we use the last coded P frame value
|
|
- get estimated of I => This call for two cases:
|
|
=> a) if num_ifi_encoded is less than 2
|
|
then return the previous encoded I frame sad
|
|
=> b) if num_ifi_encoded is more than 2, then we scale
|
|
the prev I sad by the ratio of (n-1) ifi P to n-2 ifi P
|
|
2) When P frame is getting encoded,
|
|
- get the estimated of P => No issues since we use the last coded P frame value
|
|
- get the estimated of I => Simillar to I we have two cases. To handle the b) case
|
|
extra logic had to introduced using
|
|
u1_is_n_1_p_frm_ifi_avg_sad_usable flag
|
|
*/
|
|
UWORD32 get_est_sad(est_sad_t *ps_est_sad, picture_type_e e_pic_type)
|
|
{
|
|
if(ps_est_sad->i4_use_est_intra_sad)
|
|
{
|
|
UWORD32 u4_estimated_sad;
|
|
if(e_pic_type == P_PIC)
|
|
{
|
|
u4_estimated_sad = ps_est_sad->au4_prev_frm_sad[P_PIC];
|
|
}
|
|
else if(e_pic_type == B_PIC)
|
|
{
|
|
u4_estimated_sad = ps_est_sad->au4_prev_frm_sad[B_PIC];
|
|
}
|
|
else
|
|
{
|
|
if(ps_est_sad->i4_num_ifi_encoded < 2)
|
|
{
|
|
/* Only one IFI has been encoded and so use the previous I frames SAD */
|
|
u4_estimated_sad = ps_est_sad->au4_prev_frm_sad[I_PIC];
|
|
}
|
|
else
|
|
{
|
|
/* Since the n-1 'P' frame IFI would have just accumulated the frame sads
|
|
we average it out here */
|
|
UWORD32 u4_n_1_p_frm_ifi_avg_sad, u4_n_2_p_frm_ifi_avg_sad;
|
|
number_t vq_n_1_p_frm_ifi_avg_sad, vq_n_2_p_frm_ifi_avg_sad;
|
|
number_t vq_prev_frm_sad_i;
|
|
/* If there are frames in the current IFI start using it to estimate the I frame SAD */
|
|
if(ps_est_sad->i4_num_p_frm_in_cur_ifi)
|
|
{
|
|
u4_n_1_p_frm_ifi_avg_sad =
|
|
(ps_est_sad->u4_n_p_frm_ifi_avg_sad / ps_est_sad->i4_num_p_frm_in_cur_ifi);
|
|
u4_n_2_p_frm_ifi_avg_sad = ps_est_sad->u4_n_1_p_frm_ifi_avg_sad;
|
|
}
|
|
else
|
|
{
|
|
u4_n_1_p_frm_ifi_avg_sad = ps_est_sad->u4_n_1_p_frm_ifi_avg_sad;
|
|
u4_n_2_p_frm_ifi_avg_sad = ps_est_sad->u4_n_2_p_frm_ifi_avg_sad;
|
|
}
|
|
/* If any of the previous p frame SADs are zeros we just return the previous
|
|
I frame SAD */
|
|
if(u4_n_1_p_frm_ifi_avg_sad && u4_n_2_p_frm_ifi_avg_sad)
|
|
{
|
|
SET_VAR_Q(vq_prev_frm_sad_i, ps_est_sad->au4_prev_frm_sad[I_PIC], 0);
|
|
SET_VAR_Q(vq_n_1_p_frm_ifi_avg_sad, u4_n_1_p_frm_ifi_avg_sad, 0);
|
|
SET_VAR_Q(vq_n_2_p_frm_ifi_avg_sad, u4_n_2_p_frm_ifi_avg_sad, 0);
|
|
/**************************************************************************
|
|
Estimated SAD =
|
|
(n-1)th intra frame interval(ifi) P frame Avg SAD *
|
|
(prev I frame SAD / (n-2)nd intra frame interval(ifi) P frame Avg SAD)
|
|
**************************************************************************/
|
|
mult32_var_q(vq_prev_frm_sad_i, vq_n_1_p_frm_ifi_avg_sad, &vq_prev_frm_sad_i);
|
|
div32_var_q(vq_prev_frm_sad_i, vq_n_2_p_frm_ifi_avg_sad, &vq_prev_frm_sad_i);
|
|
number_t_to_word32(vq_prev_frm_sad_i, (WORD32 *)&u4_estimated_sad);
|
|
}
|
|
else
|
|
{
|
|
u4_estimated_sad = ps_est_sad->au4_prev_frm_sad[I_PIC];
|
|
}
|
|
}
|
|
}
|
|
return u4_estimated_sad;
|
|
}
|
|
else
|
|
{
|
|
return ps_est_sad->au4_prev_frm_sad[e_pic_type];
|
|
}
|
|
}
|
|
/****************************************************************************
|
|
Function Name : update_ppic_sad
|
|
Description :
|
|
Inputs : ps_est_sad
|
|
|
|
Revision History:
|
|
DD MM YYYY Author(s) Changes (Describe the changes made)
|
|
*****************************************************************************/
|
|
WORD32 update_ppic_sad(est_sad_t *ps_est_sad, WORD32 i4_est_sad, WORD32 i4_prev_p_sad)
|
|
{
|
|
i4_est_sad = ((ps_est_sad->au4_prev_frm_sad[P_PIC]) * ((i4_est_sad << 4) / i4_prev_p_sad)) >> 4;
|
|
/* printf("i4_est_sad=%d prev_psad=%d\n",i4_est_sad,ps_est_sad->au4_prev_frm_sad[P_PIC]); */
|
|
if(i4_est_sad > (WORD32)ps_est_sad->au4_prev_frm_sad[P_PIC])
|
|
{
|
|
if(4 * i4_est_sad > 5 * i4_prev_p_sad)
|
|
i4_est_sad = (5 * i4_prev_p_sad) >> 2;
|
|
ps_est_sad->au4_prev_frm_sad[P_PIC] = i4_est_sad;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/****************************************************************************
|
|
Function Name : update_actual_sad
|
|
Description :
|
|
Inputs : ps_est_sad
|
|
|
|
Revision History:
|
|
DD MM YYYY Author(s) Changes (Describe the changes made)
|
|
*****************************************************************************/
|
|
void update_actual_sad(est_sad_t *ps_est_sad, UWORD32 u4_actual_sad, picture_type_e e_pic_type)
|
|
{
|
|
ps_est_sad->au4_prev_frm_sad[e_pic_type] = u4_actual_sad;
|
|
|
|
if(ps_est_sad->i4_use_est_intra_sad)
|
|
{
|
|
if(e_pic_type == I_PIC)
|
|
{
|
|
/* The requirement is to have two IFI before estimating I frame SAD */
|
|
if(ps_est_sad->i4_num_ifi_encoded < 2)
|
|
ps_est_sad->i4_num_ifi_encoded++;
|
|
|
|
/* Calculate the average SAD */
|
|
if(ps_est_sad->i4_num_p_frm_in_cur_ifi)
|
|
{
|
|
ps_est_sad->u4_n_p_frm_ifi_avg_sad /= ps_est_sad->i4_num_p_frm_in_cur_ifi;
|
|
}
|
|
else
|
|
{
|
|
ps_est_sad->u4_n_p_frm_ifi_avg_sad = 0;
|
|
}
|
|
/* Push the (n-1)th average SAD to the (n-2)th average SAD */
|
|
ps_est_sad->u4_n_2_p_frm_ifi_avg_sad = ps_est_sad->u4_n_1_p_frm_ifi_avg_sad;
|
|
/* Push the nth average SAD to the (n-1)th average SAD */
|
|
ps_est_sad->u4_n_1_p_frm_ifi_avg_sad = ps_est_sad->u4_n_p_frm_ifi_avg_sad;
|
|
/* Reset SAD and number of P frames */
|
|
ps_est_sad->u4_n_p_frm_ifi_avg_sad = 0;
|
|
ps_est_sad->i4_num_p_frm_in_cur_ifi = 0;
|
|
}
|
|
else
|
|
{
|
|
ps_est_sad->u4_n_p_frm_ifi_avg_sad += u4_actual_sad;
|
|
ps_est_sad->i4_num_p_frm_in_cur_ifi++;
|
|
}
|
|
}
|
|
}
|
|
/****************************************************************************
|
|
Function Name : update_prev_frame_intra_sad
|
|
Description :
|
|
Inputs : ps_est_sad
|
|
|
|
Revision History:
|
|
DD MM YYYY Author(s) Changes (Describe the changes made)
|
|
*****************************************************************************/
|
|
void update_prev_frame_intra_sad(est_sad_t *ps_est_sad, WORD32 i4_intra_frm_sad)
|
|
{
|
|
ps_est_sad->au4_prev_frm_sad[I_PIC] = i4_intra_frm_sad;
|
|
}
|
|
/****************************************************************************
|
|
Function Name : get_prev_frame_intra_sad
|
|
Description :
|
|
Inputs : ps_est_sad
|
|
|
|
Revision History:
|
|
DD MM YYYY Author(s) Changes (Describe the changes made)
|
|
*****************************************************************************/
|
|
WORD32 get_prev_frame_intra_sad(est_sad_t *ps_est_sad)
|
|
{
|
|
return ps_est_sad->au4_prev_frm_sad[I_PIC];
|
|
}
|
|
/****************************************************************************
|
|
Function Name : update_prev_frame_sad
|
|
Description :
|
|
Inputs : ps_est_sad
|
|
|
|
Revision History:
|
|
DD MM YYYY Author(s) Changes (Describe the changes made)
|
|
*****************************************************************************/
|
|
void update_prev_frame_sad(est_sad_t *ps_est_sad, WORD32 i4_frm_sad, picture_type_e e_pic_type)
|
|
{
|
|
ps_est_sad->au4_prev_frm_sad[e_pic_type] = i4_frm_sad;
|
|
}
|
|
/****************************************************************************
|
|
Function Name : get_prev_frame_sad
|
|
Description :
|
|
Inputs : ps_est_sad
|
|
|
|
Revision History:
|
|
DD MM YYYY Author(s) Changes (Describe the changes made)
|
|
*****************************************************************************/
|
|
WORD32 get_prev_frame_sad(est_sad_t *ps_est_sad, picture_type_e e_pic_type)
|
|
{
|
|
return ps_est_sad->au4_prev_frm_sad[e_pic_type];
|
|
}
|