/****************************************************************************** * * Copyright (C) 2015 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 */ /*****************************************************************************/ /* Includes */ /*****************************************************************************/ /* User include files */ #include "irc_datatypes.h" #include "irc_cntrl_param.h" #include "irc_mem_req_and_acq.h" #include "irc_est_sad.h" #include "irc_common.h" typedef struct est_sad_t { WORD32 i4_use_est_intra_sad; /* Previous frame SAD */ UWORD32 au4_prev_frm_sad[MAX_PIC_TYPE]; /* Current (nth) ifi average P frame SAD */ UWORD32 u4_n_p_frm_ifi_avg_sad; /* (n-1)th ifi average P frame SAD */ UWORD32 u4_n_1_p_frm_ifi_avg_sad; /* (n-2)th ifi average P frame SAD */ UWORD32 u4_n_2_p_frm_ifi_avg_sad; /* number of ifi encoded till now */ WORD32 i4_num_ifi_encoded; /* number of P frames in the current IFI */ WORD32 i4_num_p_frm_in_cur_ifi; } est_sad_t; WORD32 irc_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; est_sad_t s_est_sad; /* Hack for al alloc, during which we don't 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), ALIGN_128_BYTE, 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); } void irc_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; } void irc_reset_est_sad(est_sad_t *ps_est_sad) { irc_init_est_sad(ps_est_sad, ps_est_sad->i4_use_est_intra_sad); } /* * 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 irc_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 / *(prev (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]; } } void irc_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++; } } } void irc_update_actual_sad_for_intra(est_sad_t *ps_est_sad, WORD32 i4_intra_frm_cost) { if(!(ps_est_sad->i4_use_est_intra_sad)) { irc_update_actual_sad(ps_est_sad, i4_intra_frm_cost, I_PIC); } }