| /****************************************************************************** |
| * |
| * 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 Name : rc_rd_model.c */ |
| /* */ |
| /* Description : Implall the Functions to Model the */ |
| /* Rate Distortion Behaviour of the Codec over the Last */ |
| /* Few Frames. */ |
| /* */ |
| /* List of Functions : update_frame_rd_model */ |
| /* estimate_mpeg2_qp_for_resbits */ |
| /* */ |
| /* Issues / Problems : None */ |
| /* */ |
| /* Revision History : */ |
| /* DD MM YYYY Author(s) Changes (Describe the changes made) */ |
| /* 21 06 2006 ittiam Initial Version */ |
| /****************************************************************************/ |
| |
| /*****************************************************************************/ |
| /* File Includes */ |
| /*****************************************************************************/ |
| /* System include files */ |
| #include <stdarg.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <math.h> |
| |
| /* System include files */ |
| #include "ittiam_datatypes.h" |
| #include "rc_common.h" |
| #include "var_q_operator.h" |
| #include "mem_req_and_acq.h" |
| #include "rc_rd_model.h" |
| #include "rc_rd_model_struct.h" |
| |
| #if !(RC_FIXED_POINT) |
| |
| #if NON_STEADSTATE_CODE |
| WORD32 rc_rd_model_num_fill_use_free_memtab( |
| rc_rd_model_t **pps_rc_rd_model, itt_memtab_t *ps_memtab, ITT_FUNC_TYPE_E e_func_type) |
| { |
| WORD32 i4_mem_tab_idx = 0; |
| static rc_rd_model_t s_rc_rd_model_temp; |
| |
| /* 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_rc_rd_model) = &s_rc_rd_model_temp; |
| |
| /*for src rate control state structure*/ |
| if(e_func_type != GET_NUM_MEMTAB) |
| { |
| fill_memtab( |
| &ps_memtab[i4_mem_tab_idx], sizeof(rc_rd_model_t), MEM_TAB_ALIGNMENT, PERSISTENT, DDR); |
| use_or_fill_base(&ps_memtab[0], (void **)pps_rc_rd_model, e_func_type); |
| } |
| i4_mem_tab_idx++; |
| |
| return (i4_mem_tab_idx); |
| } |
| |
| void init_frm_rc_rd_model(rc_rd_model_t *ps_rd_model, UWORD8 u1_max_frames_modelled) |
| { |
| /*ps_rd_model = ps_rd_model + u1_pic_type;*/ |
| |
| ps_rd_model->u1_num_frms_in_model = 0; |
| ps_rd_model->u1_curr_frm_counter = 0; |
| ps_rd_model->u1_max_frms_to_model = u1_max_frames_modelled; |
| /* |
| ps_rd_model->u1_min_frames_for_quad_model = u1_min_frames_for_quad_model; |
| ps_rd_model->u1_min_frames_for_lin_model = u1_min_frames_for_lin_model; |
| */ |
| |
| ps_rd_model->model_coeff_a_quad = 0; |
| ps_rd_model->model_coeff_b_quad = 0; |
| ps_rd_model->model_coeff_c_quad = 0; |
| |
| ps_rd_model->model_coeff_a_lin = 0; |
| ps_rd_model->model_coeff_b_lin = 0; |
| ps_rd_model->model_coeff_c_lin = 0; |
| |
| ps_rd_model->model_coeff_a_lin_wo_int = 0; |
| ps_rd_model->model_coeff_b_lin_wo_int = 0; |
| ps_rd_model->model_coeff_c_lin_wo_int = 0; |
| } |
| |
| void reset_frm_rc_rd_model(rc_rd_model_t *ps_rd_model) |
| { |
| /*ps_rd_model = ps_rd_model + u1_pic_type;*/ |
| |
| ps_rd_model->u1_num_frms_in_model = 0; |
| ps_rd_model->u1_curr_frm_counter = 0; |
| ps_rd_model->model_coeff_a_quad = 0; |
| ps_rd_model->model_coeff_b_quad = 0; |
| ps_rd_model->model_coeff_c_quad = 0; |
| |
| ps_rd_model->model_coeff_a_lin = 0; |
| ps_rd_model->model_coeff_b_lin = 0; |
| ps_rd_model->model_coeff_c_lin = 0; |
| |
| ps_rd_model->model_coeff_a_lin_wo_int = 0; |
| ps_rd_model->model_coeff_b_lin_wo_int = 0; |
| ps_rd_model->model_coeff_c_lin_wo_int = 0; |
| } |
| #endif /* #if NON_STEADSTATE_CODE */ |
| |
| #if ENABLE_QUAD_MODEL |
| static UWORD8 find_model_coeffs( |
| UWORD32 *pi4_res_bits, |
| UWORD32 *pi4_sad_h264, |
| UWORD8 *pu1_num_skips, |
| UWORD8 *pui_avg_mpeg2_qp, |
| UWORD8 u1_num_frms, |
| UWORD8 u1_model_used, |
| WORD8 *pi1_frame_index, |
| model_coeff *pmc_model_coeff, |
| model_coeff *pmc_model_coeff_lin, |
| model_coeff *pmc_model_coeff_lin_wo_int, |
| rc_rd_model_t *ps_rd_model) |
| { |
| UWORD32 i; |
| UWORD8 u1_num_frms_used = 0; |
| UWORD8 u1_frm_indx; |
| |
| float sum_y = 0; |
| float sum_x_y = 0; |
| float sum_x2_y = 0; |
| float sum_x = 0; |
| float sum_x2 = 0; |
| float sum_x3 = 0; |
| float sum_x4 = 0; |
| float var_x2_y = 0; |
| float var_x_y = 0; |
| float var_x2_x = 0; |
| float var_x2_x2 = 0; |
| float var_x_x = 0; |
| float x0, y0; |
| float model_coeff_a, model_coeff_b, model_coeff_c, model_coeff_den; |
| |
| for(i = 0; i < u1_num_frms; i++) |
| { |
| if(-1 == pi1_frame_index[i]) |
| continue; |
| |
| u1_frm_indx = (UWORD8)pi1_frame_index[i]; |
| |
| y0 = (float)(pi4_res_bits[u1_frm_indx]); |
| x0 = (float)(pi4_sad_h264[u1_frm_indx] / (float)pui_avg_mpeg2_qp[u1_frm_indx]); |
| |
| sum_y += y0; |
| sum_x_y += x0 * y0; |
| sum_x2_y += x0 * x0 * y0; |
| sum_x += x0; |
| sum_x2 += x0 * x0; |
| sum_x3 += x0 * x0 * x0; |
| sum_x4 += x0 * x0 * x0 * x0; |
| u1_num_frms_used++; |
| } |
| |
| sum_y /= u1_num_frms_used; |
| sum_x_y /= u1_num_frms_used; |
| sum_x2_y /= u1_num_frms_used; |
| sum_x /= u1_num_frms_used; |
| sum_x2 /= u1_num_frms_used; |
| sum_x3 /= u1_num_frms_used; |
| sum_x4 /= u1_num_frms_used; |
| |
| #if !QUAD |
| u1_model_used = LIN_MODEL; |
| #endif |
| |
| if((QUAD_MODEL == u1_model_used) && (u1_num_frms_used <= MIN_FRAMES_FOR_QUAD_MODEL)) |
| { |
| u1_model_used = LIN_MODEL; |
| } |
| |
| if(QUAD_MODEL == u1_model_used) |
| { |
| var_x2_y = sum_x2_y - sum_x2 * sum_y; |
| var_x_y = sum_x_y - sum_x * sum_y; |
| var_x2_x = sum_x3 - sum_x2 * sum_x; |
| var_x2_x2 = sum_x4 - sum_x2 * sum_x2; |
| var_x_x = sum_x2 - sum_x * sum_x; |
| |
| model_coeff_den = (var_x2_x * var_x2_x - var_x2_x2 * var_x_x); |
| |
| if(0 != model_coeff_den) |
| { |
| model_coeff_b = (var_x_y * var_x2_x - var_x2_y * var_x_x); |
| model_coeff_b /= model_coeff_den; |
| |
| model_coeff_a = (var_x2_y * var_x2_x - var_x_y * var_x2_x2); |
| model_coeff_a /= model_coeff_den; |
| |
| model_coeff_c = sum_y - (model_coeff_a * sum_x) - (model_coeff_b * sum_x2); |
| } |
| |
| pmc_model_coeff[0] = model_coeff_b; |
| pmc_model_coeff[1] = model_coeff_a; |
| pmc_model_coeff[2] = model_coeff_c; |
| } |
| |
| if(NULL != pmc_model_coeff_lin) |
| { |
| var_x_y = sum_x_y - sum_x * sum_y; |
| var_x_x = sum_x2 - sum_x * sum_x; |
| |
| if(0 != var_x_x) |
| { |
| model_coeff_a = (var_x_y / var_x_x); |
| model_coeff_c = sum_y - (model_coeff_a * sum_x); |
| /*model_coeff_b = 0;*/ |
| model_coeff_b = model_coeff_a; |
| |
| pmc_model_coeff_lin[0] = model_coeff_b; |
| pmc_model_coeff_lin[1] = model_coeff_a; |
| pmc_model_coeff_lin[2] = model_coeff_c; |
| } |
| } |
| |
| if(NULL != pmc_model_coeff_lin_wo_int) |
| { |
| UWORD8 u1_curr_frame_index; |
| UWORD8 u1_avgqp_prvfrm; |
| UWORD32 u4_prevfrm_bits, u4_prevfrm_sad; |
| |
| u1_curr_frame_index = ps_rd_model->u1_curr_frm_counter; |
| if(0 == u1_curr_frame_index) |
| u1_curr_frame_index = (MAX_FRAMES_MODELLED - 1); |
| else |
| u1_curr_frame_index--; |
| |
| u1_avgqp_prvfrm = ps_rd_model->pu1_avg_qp[u1_curr_frame_index]; |
| u4_prevfrm_bits = ps_rd_model->pi4_res_bits[u1_curr_frame_index]; |
| u4_prevfrm_sad = ps_rd_model->pi4_sad[u1_curr_frame_index]; |
| |
| if(0 != u4_prevfrm_sad) |
| model_coeff_a = (float)(u4_prevfrm_bits * u1_avgqp_prvfrm) / u4_prevfrm_sad; |
| else |
| model_coeff_a = 0; |
| |
| model_coeff_b = 0; |
| model_coeff_c = 0; |
| |
| pmc_model_coeff_lin_wo_int[0] = model_coeff_b; |
| pmc_model_coeff_lin_wo_int[1] = model_coeff_a; |
| pmc_model_coeff_lin_wo_int[2] = model_coeff_c; |
| } |
| |
| return u1_model_used; |
| } |
| |
| static WORD8 refine_set_of_points( |
| UWORD32 *pi4_res_bits, |
| UWORD32 *pi4_sad_h264, |
| UWORD8 *pu1_num_skips, |
| UWORD8 *pui_avg_mpeg2_qp, |
| UWORD8 u1_num_frms, |
| WORD8 *pi1_frame_index, |
| model_coeff *pmc_model_coeff, |
| float *pfl_avg_deviation) |
| { |
| float fl_avg_deviation, fl_estimated_bits, fl_deviation, x_val; |
| UWORD8 u1_return_value = 1; |
| UWORD32 i; |
| UWORD8 u1_num_frms_used, u1_frm_indx; |
| |
| u1_num_frms_used = 0; |
| fl_avg_deviation = 0; |
| for(i = 0; i < u1_num_frms; i++) |
| { |
| if(-1 == pi1_frame_index[i]) |
| continue; |
| |
| u1_frm_indx = (UWORD8)pi1_frame_index[i]; |
| x_val = pi4_sad_h264[u1_frm_indx] / (float)pui_avg_mpeg2_qp[u1_frm_indx]; |
| |
| fl_estimated_bits = (pmc_model_coeff[0] * x_val * x_val) + (pmc_model_coeff[1] * x_val) + |
| (pmc_model_coeff[2]); |
| |
| fl_deviation = |
| fabs(pi4_res_bits[u1_frm_indx] - fl_estimated_bits) / (float)pi4_res_bits[u1_frm_indx]; |
| fl_deviation = fl_deviation * fl_deviation; |
| fl_avg_deviation += fl_deviation; |
| u1_num_frms_used++; |
| } |
| |
| fl_avg_deviation /= u1_num_frms_used; |
| /*fl_avg_deviation = sqrt(fl_avg_deviation);*/ |
| fl_avg_deviation = (fl_avg_deviation); |
| |
| for(i = 0; i < u1_num_frms; i++) |
| { |
| if((-1 == pi1_frame_index[i]) && (i != 0)) |
| continue; |
| |
| u1_frm_indx = (UWORD8)pi1_frame_index[i]; |
| |
| x_val = pi4_sad_h264[u1_frm_indx] / (float)pui_avg_mpeg2_qp[u1_frm_indx]; |
| |
| fl_estimated_bits = (pmc_model_coeff[0] * x_val * x_val) + (pmc_model_coeff[1] * x_val) + |
| (pmc_model_coeff[2]); |
| |
| fl_deviation = |
| fabs(pi4_res_bits[u1_frm_indx] - fl_estimated_bits) / (float)pi4_res_bits[u1_frm_indx]; |
| |
| fl_deviation = fl_deviation * fl_deviation; |
| |
| if(fl_deviation > (fl_avg_deviation)) |
| { |
| pi1_frame_index[i] = -1; |
| } |
| } |
| |
| if(fl_avg_deviation > 0.0625) |
| u1_return_value = 0; |
| if(fl_avg_deviation < 0.0225) |
| u1_return_value = 2; |
| |
| *pfl_avg_deviation = fl_avg_deviation; |
| |
| return (u1_return_value); |
| } |
| static void calc_avg_sqr_dev_for_model( |
| UWORD32 *pi4_res_bits, |
| UWORD32 *pi4_sad_h264, |
| UWORD8 *pu1_num_skips, |
| UWORD8 *pui_avg_mpeg2_qp, |
| UWORD8 u1_num_frms, |
| WORD8 *pi1_frame_index, |
| model_coeff *pmc_model_coeff, |
| float *pfl_avg_deviation) |
| { |
| float fl_avg_deviation, fl_estimated_bits, fl_deviation, x_val; |
| UWORD8 u1_return_value = 1; |
| UWORD32 i; |
| UWORD8 u1_num_frms_used, u1_frm_indx; |
| |
| u1_num_frms_used = 0; |
| fl_avg_deviation = 0; |
| for(i = 0; i < u1_num_frms; i++) |
| { |
| if(-1 == pi1_frame_index[i]) |
| continue; |
| |
| u1_frm_indx = (UWORD8)pi1_frame_index[i]; |
| |
| u1_frm_indx = (UWORD8)i; |
| x_val = pi4_sad_h264[u1_frm_indx] / (float)pui_avg_mpeg2_qp[u1_frm_indx]; |
| |
| fl_estimated_bits = (pmc_model_coeff[1] * x_val) + (pmc_model_coeff[2]); |
| |
| fl_deviation = |
| fabs(pi4_res_bits[u1_frm_indx] - fl_estimated_bits) / (float)pi4_res_bits[u1_frm_indx]; |
| fl_deviation = fl_deviation * fl_deviation; |
| fl_avg_deviation += fl_deviation; |
| u1_num_frms_used++; |
| } |
| |
| fl_avg_deviation /= u1_num_frms_used; |
| /*fl_avg_deviation = sqrt(fl_avg_deviation);*/ |
| fl_avg_deviation = (fl_avg_deviation); |
| |
| *pfl_avg_deviation = fl_avg_deviation; |
| /*return (u1_return_value);*/ |
| } |
| static void update_frame_rd_model(rc_rd_model_t *ps_rd_model) |
| { |
| WORD8 pi1_frame_index[MAX_FRAMES_MODELLED], pi1_frame_index_initial[MAX_FRAMES_MODELLED]; |
| |
| UWORD8 u1_num_skips_temp; |
| UWORD8 u1_avg_mpeg2_qp_temp, u1_min_mpeg2_qp, u1_max_mpeg2_qp; |
| UWORD8 u1_num_frms_input, u1_num_active_frames, u1_reject_frame; |
| UWORD32 u4_num_skips; |
| |
| UWORD8 u1_min2_mpeg2_qp, u1_max2_mpeg2_qp; |
| UWORD8 u1_min_qp_frame_indx, u1_max_qp_frame_indx; |
| UWORD8 pu1_num_frames[MPEG2_QP_ELEM]; |
| model_coeff model_coeff_array[3], model_coeff_array_lin[3], model_coeff_array_lin_wo_int[3]; |
| UWORD32 i; |
| UWORD8 u1_curr_frame_index; |
| UWORD8 u1_quad_model_valid, u1_lin_model_valid; |
| |
| float fl_quad_avg_dev, fl_lin_avg_dev; |
| |
| UWORD8 u1_check_model; |
| |
| /*ps_rd_model += u1_pic_type;*/ |
| |
| u1_curr_frame_index = ps_rd_model->u1_curr_frm_counter; |
| |
| ps_rd_model->u1_model_used = QUAD_MODEL; |
| |
| if(0 == u1_curr_frame_index) |
| u1_curr_frame_index = (MAX_FRAMES_MODELLED - 1); |
| else |
| u1_curr_frame_index--; |
| |
| /************************************************************************/ |
| /* Rearrange data to be fed into a Linear Regression Module */ |
| /* Module finds a,b,c such that */ |
| /* y = ax + bx^2 + c */ |
| /************************************************************************/ |
| u4_num_skips = 0; |
| u1_num_frms_input = 0; |
| memset(pu1_num_frames, 0, MPEG2_QP_ELEM); |
| memset(pi1_frame_index, -1, MAX_FRAMES_MODELLED); |
| u1_min_mpeg2_qp = MAX_MPEG2_QP; |
| u1_max_mpeg2_qp = 0; |
| |
| u1_num_active_frames = ps_rd_model->u1_num_frms_in_model; |
| if(u1_num_active_frames > MAX_ACTIVE_FRAMES) |
| u1_num_active_frames = MAX_ACTIVE_FRAMES; |
| |
| /************************************************************************/ |
| /* Choose the set of Points to be used for MSE fit of Quadratic model */ |
| /* Points chosen are spread across the Qp range. Max of 2 points are */ |
| /* chosen for a Qp. */ |
| /************************************************************************/ |
| for(i = 0; i < u1_num_active_frames; i++) |
| { |
| u1_reject_frame = 0; |
| u1_num_skips_temp = ps_rd_model->pu1_num_skips[u1_curr_frame_index]; |
| u1_avg_mpeg2_qp_temp = ps_rd_model->pu1_avg_qp[u1_curr_frame_index]; |
| |
| if((0 == u4_num_skips) && (0 != u1_num_skips_temp)) |
| u1_reject_frame = 1; |
| if((1 == u4_num_skips) && (u1_num_skips_temp > 1)) |
| u1_reject_frame = 1; |
| if(pu1_num_frames[u1_avg_mpeg2_qp_temp] >= 2) |
| u1_reject_frame = 1; |
| |
| if(0 == i) |
| u1_reject_frame = 0; |
| |
| if(0 == u1_reject_frame) |
| { |
| pi1_frame_index[u1_num_frms_input] = (WORD8)u1_curr_frame_index; |
| pu1_num_frames[u1_avg_mpeg2_qp_temp] += 1; |
| |
| if(u1_min_mpeg2_qp > u1_avg_mpeg2_qp_temp) |
| u1_min_mpeg2_qp = u1_avg_mpeg2_qp_temp; |
| if(u1_max_mpeg2_qp < u1_avg_mpeg2_qp_temp) |
| u1_max_mpeg2_qp = u1_avg_mpeg2_qp_temp; |
| |
| u1_num_frms_input++; |
| } |
| |
| if(0 == u1_curr_frame_index) |
| u1_curr_frame_index = (MAX_FRAMES_MODELLED - 1); |
| else |
| u1_curr_frame_index--; |
| } |
| |
| /************************************************************************/ |
| /* Add Pivot Points to the Data set to be used for finding Quadratic */ |
| /* Model Coeffs. These will help in constraining the shape of Quadratic*/ |
| /* to adapt too much to the Local deviations. */ |
| /************************************************************************/ |
| u1_min2_mpeg2_qp = u1_min_mpeg2_qp; |
| u1_max2_mpeg2_qp = u1_max_mpeg2_qp; |
| u1_min_qp_frame_indx = INVALID_FRAME_INDEX; |
| u1_max_qp_frame_indx = INVALID_FRAME_INDEX; |
| |
| /* Loop runnning over the Stored Frame Level Data |
| to find frames of MinQp and MaxQp */ |
| for(; i < ps_rd_model->u1_num_frms_in_model; i++) |
| { |
| u1_num_skips_temp = ps_rd_model->pu1_num_skips[u1_curr_frame_index]; |
| u1_avg_mpeg2_qp_temp = ps_rd_model->pu1_avg_qp[u1_curr_frame_index]; |
| |
| if(((0 == u4_num_skips) && (0 != u1_num_skips_temp)) || |
| ((1 == u4_num_skips) && (u1_num_skips_temp > 1))) |
| continue; |
| |
| if(u1_min2_mpeg2_qp > u1_avg_mpeg2_qp_temp) |
| { |
| u1_min2_mpeg2_qp = u1_avg_mpeg2_qp_temp; |
| u1_min_qp_frame_indx = u1_curr_frame_index; |
| } |
| if(u1_max2_mpeg2_qp < u1_avg_mpeg2_qp_temp) |
| { |
| u1_max2_mpeg2_qp = u1_avg_mpeg2_qp_temp; |
| u1_max_qp_frame_indx = u1_curr_frame_index; |
| } |
| if(0 == u1_curr_frame_index) |
| u1_curr_frame_index = (MAX_FRAMES_MODELLED - 1); |
| else |
| u1_curr_frame_index--; |
| } |
| |
| /* Add the Chosen Points to the regression data set */ |
| if(INVALID_FRAME_INDEX != u1_min_qp_frame_indx) |
| { |
| pi1_frame_index[u1_num_frms_input] = (WORD8)u1_min_qp_frame_indx; |
| u1_num_frms_input++; |
| } |
| if(INVALID_FRAME_INDEX != u1_max_qp_frame_indx) |
| { |
| pi1_frame_index[u1_num_frms_input] = (WORD8)u1_max_qp_frame_indx; |
| u1_num_frms_input++; |
| } |
| memcpy(pi1_frame_index_initial, pi1_frame_index, MAX_FRAMES_MODELLED); |
| |
| if(QUAD_MODEL == ps_rd_model->u1_model_used) |
| { |
| if(u1_num_frms_input < (MIN_FRAMES_FOR_QUAD_MODEL)) |
| ps_rd_model->u1_model_used = LIN_MODEL; |
| if((WORD32)u1_max_mpeg2_qp < ((WORD32)(21 * u1_min_mpeg2_qp) >> 4)) |
| ps_rd_model->u1_model_used = LIN_MODEL; |
| } |
| |
| if(LIN_MODEL == ps_rd_model->u1_model_used) |
| { |
| if(u1_num_frms_input < MIN_FRAMES_FOR_LIN_MODEL) |
| ps_rd_model->u1_model_used = PREV_FRAME_MODEL; |
| if((WORD32)u1_max_mpeg2_qp < ((WORD32)(19 * u1_min_mpeg2_qp) >> 4)) |
| ps_rd_model->u1_model_used = PREV_FRAME_MODEL; |
| } |
| |
| /***** Call the Module to Return the Coeffs for the Fed Data *****/ |
| ps_rd_model->u1_model_used = find_model_coeffs( |
| ps_rd_model->pi4_res_bits, |
| ps_rd_model->pi4_sad, |
| ps_rd_model->pu1_num_skips, |
| ps_rd_model->pu1_avg_qp, |
| u1_num_frms_input, |
| ps_rd_model->u1_model_used, |
| pi1_frame_index, |
| model_coeff_array, |
| model_coeff_array_lin, |
| model_coeff_array_lin_wo_int, |
| ps_rd_model); |
| |
| if((model_coeff_array_lin[2] > 0) || (model_coeff_array_lin[0] < 0)) |
| u1_lin_model_valid = 0; |
| else |
| { |
| u1_lin_model_valid = 1; |
| /* lin deviation calculation */ |
| calc_avg_sqr_dev_for_model( |
| ps_rd_model->pi4_res_bits, |
| ps_rd_model->pi4_sad, |
| ps_rd_model->pu1_num_skips, |
| ps_rd_model->pu1_avg_qp, |
| u1_num_frms_input, |
| pi1_frame_index_initial, |
| model_coeff_array_lin, |
| &fl_lin_avg_dev); |
| } |
| |
| if(QUAD_MODEL == ps_rd_model->u1_model_used) |
| { |
| u1_check_model = refine_set_of_points( |
| ps_rd_model->pi4_res_bits, |
| ps_rd_model->pi4_sad, |
| ps_rd_model->pu1_num_skips, |
| ps_rd_model->pu1_avg_qp, |
| u1_num_frms_input, |
| pi1_frame_index, |
| model_coeff_array, |
| &fl_quad_avg_dev); |
| |
| if(2 == u1_check_model) |
| { |
| ps_rd_model->u1_model_used = QUAD_MODEL; |
| } |
| else |
| { |
| /*******************************************************************/ |
| /* Make sure that some of the Pivot Points are used in the Refined */ |
| /* data set. 1. Previous Frame */ |
| /*******************************************************************/ |
| /*pi1_frame_index[0] = ps_rd_model->u1_curr_frm_counter;*/ |
| |
| ps_rd_model->u1_model_used = find_model_coeffs( |
| ps_rd_model->pi4_res_bits, |
| ps_rd_model->pi4_sad, |
| ps_rd_model->pu1_num_skips, |
| ps_rd_model->pu1_avg_qp, |
| u1_num_frms_input, |
| ps_rd_model->u1_model_used, |
| pi1_frame_index, |
| model_coeff_array, |
| NULL, |
| NULL, |
| ps_rd_model); |
| |
| u1_check_model = refine_set_of_points( |
| ps_rd_model->pi4_res_bits, |
| ps_rd_model->pi4_sad, |
| ps_rd_model->pu1_num_skips, |
| ps_rd_model->pu1_avg_qp, |
| u1_num_frms_input, |
| pi1_frame_index, |
| model_coeff_array, |
| &fl_quad_avg_dev); |
| |
| if((0 == u1_check_model)) |
| { |
| #if RC_MODEL_USED_BUG_FIX |
| if((fl_lin_avg_dev < fl_quad_avg_dev) && (1 == u1_lin_model_valid)) |
| #endif |
| ps_rd_model->u1_model_used = LIN_MODEL; |
| } |
| } |
| } |
| |
| if(QUAD_MODEL == ps_rd_model->u1_model_used) |
| { |
| /*min_res_bits = model_coeff_c - |
| ((model_coeff_a * model_coeff_a) / (4 * model_coeff_b));*/ |
| |
| if(model_coeff_array[0] < 0) |
| ps_rd_model->u1_model_used = LIN_MODEL; |
| |
| /*if ((model_coeff_a * model_coeff_b) > 0) |
| u1_model_used = LIN_MODEL;*/ |
| } |
| if(LIN_MODEL == ps_rd_model->u1_model_used) |
| { |
| if((model_coeff_array_lin[2] > 0) || (model_coeff_array_lin[0] < 0)) |
| ps_rd_model->u1_model_used = PREV_FRAME_MODEL; |
| } |
| |
| #if RC_MODEL_USED_BUG_FIX |
| /* Another threshold of .25 on deviation i.e. deviation greater than 25% */ |
| if((QUAD_MODEL == ps_rd_model->u1_model_used) && (fl_quad_avg_dev > .25)) |
| ps_rd_model->u1_model_used = PREV_FRAME_MODEL; |
| |
| if((LIN_MODEL == ps_rd_model->u1_model_used) && (fl_lin_avg_dev > .25)) |
| ps_rd_model->u1_model_used = PREV_FRAME_MODEL; |
| #endif /* #if RC_MODEL_USED_BUG_FIX */ |
| |
| ps_rd_model->model_coeff_b_quad = model_coeff_array[0]; |
| ps_rd_model->model_coeff_a_quad = model_coeff_array[1]; |
| ps_rd_model->model_coeff_c_quad = model_coeff_array[2]; |
| |
| ps_rd_model->model_coeff_b_lin = model_coeff_array_lin[0]; |
| ps_rd_model->model_coeff_a_lin = model_coeff_array_lin[1]; |
| ps_rd_model->model_coeff_c_lin = model_coeff_array_lin[2]; |
| |
| ps_rd_model->model_coeff_b_lin_wo_int = model_coeff_array_lin_wo_int[0]; |
| ps_rd_model->model_coeff_a_lin_wo_int = model_coeff_array_lin_wo_int[1]; |
| ps_rd_model->model_coeff_c_lin_wo_int = model_coeff_array_lin_wo_int[2]; |
| |
| /*ps_rd_model->u1_model_used = PREV_FRAME_MODEL;*/ |
| } |
| #endif /* ENABLE_QUAD_MODEL */ |
| |
| UWORD32 estimate_bits_for_qp(rc_rd_model_t *ps_rd_model, UWORD32 u4_estimated_sad, UWORD8 u1_avg_qp) |
| { |
| float fl_num_bits; |
| /*ps_rd_model += u1_curr_pic_type;*/ |
| |
| { |
| fl_num_bits = |
| ps_rd_model->model_coeff_a_lin_wo_int * ((float)(u4_estimated_sad / u1_avg_qp)); |
| } |
| |
| return ((UWORD32)fl_num_bits); |
| } |
| |
| UWORD8 find_qp_for_target_bits( |
| rc_rd_model_t *ps_rd_model, |
| UWORD32 u4_target_res_bits, |
| UWORD32 u4_estimated_sad, |
| UWORD8 u1_min_qp, |
| UWORD8 u1_max_qp) |
| { |
| UWORD8 u1_qp; |
| float x_value, f_qp; |
| /*ps_rd_model += u1_curr_pic_type;*/ |
| #if ENABLE_QUAD_MODEL |
| if(QUAD_MODEL == ps_rd_model->u1_model_used) |
| { |
| float det; |
| det = (ps_rd_model->model_coeff_a_quad * ps_rd_model->model_coeff_a_quad) - |
| (4 * (ps_rd_model->model_coeff_b_quad) * |
| (ps_rd_model->model_coeff_c_quad - u4_target_res_bits)); |
| |
| if(det > 0) |
| { |
| x_value = sqrt(det); |
| |
| x_value = |
| (x_value - ps_rd_model->model_coeff_a_quad) / (2 * ps_rd_model->model_coeff_b_quad); |
| } |
| else |
| ps_rd_model->u1_model_used = PREV_FRAME_MODEL; |
| } |
| |
| if(LIN_MODEL == ps_rd_model->u1_model_used) |
| { |
| x_value = ((float)u4_target_res_bits - ps_rd_model->model_coeff_c_lin) / |
| (ps_rd_model->model_coeff_b_lin); |
| } |
| #else |
| ps_rd_model->u1_model_used = PREV_FRAME_MODEL; |
| #endif |
| |
| if(PREV_FRAME_MODEL == ps_rd_model->u1_model_used) |
| { |
| x_value = (float)u4_target_res_bits / ps_rd_model->model_coeff_a_lin_wo_int; |
| } |
| |
| if(0 != x_value) |
| f_qp = u4_estimated_sad / x_value; |
| else |
| f_qp = 255; |
| |
| if(f_qp > 255) |
| f_qp = 255; |
| |
| /* Truncating the QP to the Max and Min Qp values possible */ |
| if(f_qp < u1_min_qp) |
| f_qp = u1_min_qp; |
| if(f_qp > u1_max_qp) |
| f_qp = u1_max_qp; |
| |
| u1_qp = (UWORD8)(f_qp + 0.5); |
| |
| return u1_qp; |
| } |
| |
| void add_frame_to_rd_model( |
| rc_rd_model_t *ps_rd_model, |
| UWORD32 i4_res_bits, |
| UWORD8 u1_avg_mp2qp, |
| UWORD32 i4_sad_h264, |
| UWORD8 u1_num_skips) |
| { |
| UWORD8 u1_curr_frame_index; |
| /*ps_rd_model += u1_curr_pic_type;*/ |
| u1_curr_frame_index = ps_rd_model->u1_curr_frm_counter; |
| /*** Insert the Present Frame Data into the RD Model State Memory ***/ |
| ps_rd_model->pi4_res_bits[u1_curr_frame_index] = i4_res_bits; |
| ps_rd_model->pi4_sad[u1_curr_frame_index] = i4_sad_h264; |
| ps_rd_model->pu1_num_skips[u1_curr_frame_index] = u1_num_skips; |
| ps_rd_model->pu1_avg_qp[u1_curr_frame_index] = u1_avg_mp2qp; |
| |
| ps_rd_model->u1_curr_frm_counter++; |
| if(MAX_FRAMES_MODELLED == ps_rd_model->u1_curr_frm_counter) |
| ps_rd_model->u1_curr_frm_counter = 0; |
| |
| if(ps_rd_model->u1_num_frms_in_model < ps_rd_model->u1_max_frms_to_model) |
| { |
| ps_rd_model->u1_num_frms_in_model++; |
| } |
| update_frame_rd_model(ps_rd_model); |
| } |
| |
| WORD32 calc_per_frm_bits( |
| rc_rd_model_t *ps_rd_model, /* array of model structs */ |
| UWORD16 *pu2_num_pics_of_a_pic_type, /* N1, N2,...Nk */ |
| UWORD8 * |
| pu1_update_pic_type_model, /* flag which tells whether or not to update model coefficients of a particular pic-type */ |
| UWORD8 u1_num_pic_types, /* value of k */ |
| UWORD32 * |
| pu4_num_skip_of_a_pic_type, /* the number of skips of that pic-type. It "may" be used to update the model coefficients at a later point. Right now it is not being used at all. */ |
| UWORD8 u1_base_pic_type, /* base pic type index wrt which alpha & beta are calculated */ |
| float *pfl_gamma, /* gamma_i = beta_i / alpha_i */ |
| float *pfl_eta, |
| UWORD8 |
| u1_curr_pic_type, /* the current pic-type for which the targetted bits need to be computed */ |
| UWORD32 |
| u4_bits_for_sub_gop, /* the number of bits to be consumed for the remaining part of sub-gop */ |
| UWORD32 u4_curr_estimated_sad, |
| UWORD8 *pu1_curr_pic_type_qp) /* output of this function */ |
| { |
| WORD32 i4_per_frm_bits_Ti; |
| UWORD8 u1_i; |
| rc_rd_model_t *ps_rd_model_of_pic_type; |
| |
| /* first part of this function updates all the model coefficients */ |
| /*for all the pic-types */ |
| { |
| for(u1_i = 0; u1_i < u1_num_pic_types; u1_i++) |
| { |
| if((0 != pu2_num_pics_of_a_pic_type[u1_i]) && (1 == pu1_update_pic_type_model[u1_i])) |
| { |
| /* ps_rd_model_of_pic_type = ps_rd_model + u1_i; */ |
| |
| update_frame_rd_model(&ps_rd_model[u1_i]); |
| } |
| } |
| } |
| |
| /* The second part of this function deals with solving the |
| equation using all the pic-types models */ |
| |
| { |
| UWORD8 u1_combined_model_used; |
| |
| /* first choose the model to be used */ |
| u1_combined_model_used = QUAD_MODEL; |
| |
| for(u1_i = 0; u1_i < u1_num_pic_types; u1_i++) |
| { |
| ps_rd_model_of_pic_type = ps_rd_model + u1_i; |
| |
| if((0 != pu2_num_pics_of_a_pic_type[u1_i]) && |
| (QUAD_MODEL != ps_rd_model_of_pic_type->u1_model_used)) |
| { |
| u1_combined_model_used = LIN_MODEL; |
| break; |
| } |
| } |
| |
| if(u1_combined_model_used == LIN_MODEL) |
| { |
| for(u1_i = 0; u1_i < u1_num_pic_types; u1_i++) |
| { |
| ps_rd_model_of_pic_type = ps_rd_model + u1_i; |
| |
| if((0 != pu2_num_pics_of_a_pic_type[u1_i]) && |
| (QUAD_MODEL != ps_rd_model_of_pic_type->u1_model_used) && |
| (LIN_MODEL != ps_rd_model_of_pic_type->u1_model_used)) |
| { |
| u1_combined_model_used = PREV_FRAME_MODEL; |
| break; |
| } |
| } |
| } |
| |
| /* solve the equation for the */ |
| { |
| model_coeff eff_A; |
| model_coeff eff_B; |
| model_coeff eff_C; |
| float fl_determinant; |
| float fl_sad_by_qp_base; |
| float fl_sad_by_qp_curr_frm; |
| float fl_qp_curr_frm; |
| float fl_bits_for_curr_frm; |
| |
| /* If the combined chosen model is quad model */ |
| if(QUAD_MODEL == u1_combined_model_used) |
| { |
| eff_A = 0.0; |
| eff_B = 0.0; |
| eff_C = 0.0; |
| for(u1_i = 0; u1_i < u1_num_pic_types; u1_i++) |
| { |
| ps_rd_model_of_pic_type = ps_rd_model + u1_i; |
| |
| eff_A += |
| ((pfl_eta[u1_i] + pu2_num_pics_of_a_pic_type[u1_i] - 1) * |
| ps_rd_model_of_pic_type->model_coeff_a_quad * pfl_gamma[u1_i]); |
| eff_B += |
| ((pfl_eta[u1_i] * pfl_eta[u1_i] + pu2_num_pics_of_a_pic_type[u1_i] - 1) * |
| ps_rd_model_of_pic_type->model_coeff_b_quad * pfl_gamma[u1_i] * |
| pfl_gamma[u1_i]); |
| eff_C += |
| (pu2_num_pics_of_a_pic_type[u1_i] * |
| ps_rd_model_of_pic_type->model_coeff_c_quad); |
| } |
| eff_C -= u4_bits_for_sub_gop; |
| |
| fl_determinant = eff_A * eff_A - 4 * eff_B * eff_C; |
| |
| if(fl_determinant < 0) |
| { |
| u1_combined_model_used = |
| PREV_FRAME_MODEL; /* TO BE replaced by LIN_MODEL later */ |
| } |
| else |
| { |
| fl_determinant = sqrt(fl_determinant); |
| |
| fl_sad_by_qp_base = fl_determinant - eff_A; |
| fl_sad_by_qp_base = fl_sad_by_qp_base / (2 * eff_B); |
| |
| fl_sad_by_qp_curr_frm = |
| fl_sad_by_qp_base * pfl_gamma[u1_curr_pic_type] * pfl_eta[u1_curr_pic_type]; |
| |
| ps_rd_model_of_pic_type = ps_rd_model + u1_curr_pic_type; |
| |
| fl_bits_for_curr_frm = |
| ps_rd_model_of_pic_type->model_coeff_a_quad * fl_sad_by_qp_curr_frm + |
| ps_rd_model_of_pic_type->model_coeff_b_quad * fl_sad_by_qp_curr_frm * |
| fl_sad_by_qp_curr_frm + |
| ps_rd_model_of_pic_type->model_coeff_c_quad; |
| } |
| } |
| |
| /* If the combined chosen model is linear model with an intercept */ |
| if(LIN_MODEL == u1_combined_model_used) |
| { |
| eff_A = 0.0; |
| eff_B = 0.0; |
| eff_C = 0.0; |
| for(u1_i = 0; u1_i < u1_num_pic_types; u1_i++) |
| { |
| ps_rd_model_of_pic_type = ps_rd_model + u1_i; |
| |
| eff_A += |
| ((pfl_eta[u1_i] + pu2_num_pics_of_a_pic_type[u1_i] - 1) * |
| ps_rd_model_of_pic_type->model_coeff_a_lin * pfl_gamma[u1_i]); |
| |
| eff_C += |
| (pu2_num_pics_of_a_pic_type[u1_i] * |
| ps_rd_model_of_pic_type->model_coeff_c_lin); |
| } |
| eff_C -= u4_bits_for_sub_gop; |
| |
| fl_determinant = (-(eff_C / eff_A)); |
| |
| if((fl_determinant) <= 0) |
| { |
| u1_combined_model_used = PREV_FRAME_MODEL; |
| } |
| else |
| { |
| fl_sad_by_qp_base = fl_determinant; |
| |
| fl_sad_by_qp_curr_frm = |
| fl_sad_by_qp_base * pfl_gamma[u1_curr_pic_type] * pfl_eta[u1_curr_pic_type]; |
| |
| ps_rd_model_of_pic_type = ps_rd_model + u1_curr_pic_type; |
| |
| fl_bits_for_curr_frm = |
| ps_rd_model_of_pic_type->model_coeff_a_lin * fl_sad_by_qp_curr_frm + |
| ps_rd_model_of_pic_type->model_coeff_c_lin; |
| } |
| } |
| |
| /* If the combined chosen model is linear model without an intercept */ |
| if(PREV_FRAME_MODEL == u1_combined_model_used) |
| { |
| eff_A = 0.0; |
| eff_B = 0.0; |
| eff_C = 0.0; |
| for(u1_i = 0; u1_i < u1_num_pic_types; u1_i++) |
| { |
| ps_rd_model_of_pic_type = ps_rd_model + u1_i; |
| |
| eff_A += |
| ((pfl_eta[u1_i] + pu2_num_pics_of_a_pic_type[u1_i] - 1) * |
| ps_rd_model_of_pic_type->model_coeff_a_lin_wo_int * pfl_gamma[u1_i]); |
| } |
| |
| fl_sad_by_qp_base = u4_bits_for_sub_gop / eff_A; |
| |
| fl_sad_by_qp_curr_frm = |
| fl_sad_by_qp_base * pfl_gamma[u1_curr_pic_type] * pfl_eta[u1_curr_pic_type]; |
| |
| ps_rd_model_of_pic_type = ps_rd_model + u1_curr_pic_type; |
| |
| fl_bits_for_curr_frm = |
| ps_rd_model_of_pic_type->model_coeff_a_lin_wo_int * fl_sad_by_qp_curr_frm; |
| } |
| |
| /* store the model that was finally used to calculate Qp. |
| This is so that the same model is used in further calculations for this picture. */ |
| ps_rd_model_of_pic_type = ps_rd_model + u1_curr_pic_type; |
| ps_rd_model_of_pic_type->u1_model_used = u1_combined_model_used; |
| |
| i4_per_frm_bits_Ti = (WORD32)(fl_bits_for_curr_frm + 0.5); |
| |
| if(fl_sad_by_qp_curr_frm > 0) |
| fl_qp_curr_frm = (float)u4_curr_estimated_sad / fl_sad_by_qp_curr_frm; |
| else |
| fl_qp_curr_frm = 255; |
| |
| if(fl_qp_curr_frm > 255) |
| fl_qp_curr_frm = 255; |
| |
| *pu1_curr_pic_type_qp = (fl_qp_curr_frm + 0.5); |
| } |
| } |
| return (i4_per_frm_bits_Ti); |
| } |
| |
| model_coeff get_linear_coefficient(rc_rd_model_t *ps_rd_model) |
| { |
| /*UWORD32 linear_coeff: |
| linear_coeff = ps_rd_model->model_coeff_a_lin_wo_int;*/ |
| return (ps_rd_model->model_coeff_a_lin_wo_int); |
| } |
| #endif /* !(RC_FIXED_POINT) */ |
| WORD32 rc_rd_model_dummy_for_avoiding_warnings( |
| rc_rd_model_t **pps_rc_rd_model, itt_memtab_t *ps_memtab, ITT_FUNC_TYPE_E e_func_type) |
| { |
| WORD32 i4_mem_tab_idx = 0; |
| static rc_rd_model_t s_rc_rd_model_temp; |
| |
| /* 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_rc_rd_model) = &s_rc_rd_model_temp; |
| |
| /*for src rate control state structure*/ |
| if(e_func_type != GET_NUM_MEMTAB) |
| { |
| fill_memtab( |
| &ps_memtab[i4_mem_tab_idx], sizeof(rc_rd_model_t), MEM_TAB_ALIGNMENT, PERSISTENT, DDR); |
| use_or_fill_base(&ps_memtab[0], (void **)pps_rc_rd_model, e_func_type); |
| } |
| i4_mem_tab_idx++; |
| |
| return (i4_mem_tab_idx); |
| } |