/****************************************************************************** * * 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 */ /*****************************************************************************/ /* System include files */ #include "stdio.h" /* User include files */ #include "irc_datatypes.h" #include "irc_common.h" #include "irc_cntrl_param.h" #include "irc_mem_req_and_acq.h" #include "irc_rd_model.h" #include "irc_est_sad.h" #include "irc_fixed_point_error_bits.h" #include "irc_vbr_storage_vbv.h" #include "irc_picture_type.h" #include "irc_bit_allocation.h" #include "irc_mb_model_based.h" #include "irc_cbr_buffer_control.h" #include "irc_vbr_str_prms.h" #include "irc_rate_control_api.h" #include "irc_rate_control_api_structs.h" #include "irc_trace_support.h" #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define DEV_Q 4 /*Q format(Shift) for Deviation range factor */ #define HI_DEV_FCTR 22 /* 1.4*16 */ #define LO_DEV_FCTR 12 /* 0.75*16 */ #define GET_HI_DEV_QP(Qprev) (( ((WORD32) Qprev)*HI_DEV_FCTR + (1<<(DEV_Q-1)))>>DEV_Q) #define GET_LO_DEV_QP(Qprev) (( ((WORD32) Qprev)*LO_DEV_FCTR + (1<<(DEV_Q-1)))>>DEV_Q) #define CLIP_QP(Qc, hi_d, lo_d) (((Qc) < (lo_d))?((lo_d)):(((Qc) > (hi_d))?(hi_d):(Qc))) /*****************************************************************************/ /* Restricts the quantization parameter variation within delta */ /*****************************************************************************/ /* static WORD32 restrict_swing(WORD32 cur_qp, WORD32 prev_qp, WORD32 delta_qp) { if((cur_qp) - (prev_qp) > (delta_qp)) (cur_qp) = (prev_qp) + (delta_qp) ; if((prev_qp) - (cur_qp) > (delta_qp)) (cur_qp) = (prev_qp) - (delta_qp) ; return cur_qp; }*/ /***************************************************************************** Function Name : rate_control_get_init_free_memtab Description : Takes or gives memtab Inputs : pps_rate_control_api - pointer to RC api pointer ps_memtab - Memtab pointer i4_use_base - Set during init, else 0 i4_fill_base - Set during free, else 0 *****************************************************************************/ WORD32 irc_rate_control_num_fill_use_free_memtab(rate_control_handle *pps_rate_control_api, itt_memtab_t *ps_memtab, ITT_FUNC_TYPE_E e_func_type) { WORD32 i4_mem_tab_idx = 0, i; rate_control_api_t s_temp_rc_api; /* * 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_rate_control_api) = &s_temp_rc_api; /*for src rate control state structure*/ if(e_func_type != GET_NUM_MEMTAB) { fill_memtab(&ps_memtab[i4_mem_tab_idx], sizeof(rate_control_api_t), ALIGN_128_BYTE, PERSISTENT, DDR); use_or_fill_base(&ps_memtab[0], (void**)pps_rate_control_api, e_func_type); } i4_mem_tab_idx++; /* Get the memory requirement of lower modules */ i4_mem_tab_idx += irc_ba_num_fill_use_free_memtab( &pps_rate_control_api[0]->ps_bit_allocation, &ps_memtab[i4_mem_tab_idx], e_func_type); i4_mem_tab_idx += irc_cbr_buffer_num_fill_use_free_memtab( &pps_rate_control_api[0]->ps_cbr_buffer, &ps_memtab[i4_mem_tab_idx], e_func_type); i4_mem_tab_idx += irc_est_sad_num_fill_use_free_memtab( &pps_rate_control_api[0]->ps_est_sad, &ps_memtab[i4_mem_tab_idx], e_func_type); i4_mem_tab_idx += irc_mbrc_num_fill_use_free_memtab( &pps_rate_control_api[0]->ps_mb_rate_control, &ps_memtab[i4_mem_tab_idx], e_func_type); i4_mem_tab_idx += irc_vbr_vbv_num_fill_use_free_memtab( &pps_rate_control_api[0]->ps_vbr_storage_vbv, &ps_memtab[i4_mem_tab_idx], e_func_type); for(i = 0; i < MAX_PIC_TYPE; i++) { i4_mem_tab_idx += irc_rd_model_num_fill_use_free_memtab( &pps_rate_control_api[0]->aps_rd_model[i], &ps_memtab[i4_mem_tab_idx], e_func_type); } i4_mem_tab_idx += irc_pic_handling_num_fill_use_free_memtab( &pps_rate_control_api[0]->ps_pic_handling, &ps_memtab[i4_mem_tab_idx], e_func_type); return (i4_mem_tab_idx); } /***************************************************************************** Function Name : irc_initialise_rate_control Description : Initialise the rate control structure Inputs : ps_rate_control_api - api struct e_rate_control_type - VBR, CBR (NLDRC/LDRC), VBR_STREAMING u1_is_mb_level_rc_on - enabling mb level RC u4_avg_bit_rate - bit rate to achieved across the entire file size u4_peak_bit_rate - max possible drain rate u4_frame_rate - number of frames in 1000 seconds u4_intra_frame_interval - num frames between two I frames *au1_init_qp - init_qp for I,P,B *****************************************************************************/ void irc_initialise_rate_control(rate_control_api_t *ps_rate_control_api, rc_type_e e_rate_control_type, UWORD8 u1_is_mb_level_rc_on, UWORD32 u4_avg_bit_rate, UWORD32 *pu4_peak_bit_rate, UWORD32 u4_min_bit_rate, UWORD32 u4_frame_rate, UWORD32 u4_max_delay, UWORD32 u4_intra_frame_interval, WORD32 i4_inter_frm_int, UWORD8 *pu1_init_qp, UWORD32 u4_max_vbv_buff_size, WORD32 i4_max_inter_frm_int, WORD32 i4_is_gop_closed, UWORD8 *pu1_min_max_qp, WORD32 i4_use_est_intra_sad, UWORD32 u4_src_ticks, UWORD32 u4_tgt_ticks) { WORD32 i; UWORD32 u4_frms_in_delay_prd = (u4_frame_rate * u4_max_delay) / 1000000; ps_rate_control_api->e_rc_type = e_rate_control_type; ps_rate_control_api->u1_is_mb_level_rc_on = u1_is_mb_level_rc_on; trace_printf((const WORD8*)"RC type = %d\n", e_rate_control_type); /* Set the avg_bitrate_changed flag for each pic_type to 0 */ for(i = 0; i < MAX_PIC_TYPE; i++) { ps_rate_control_api->au1_avg_bitrate_changed[i] = 0; } /* Initialize the pic_handling module */ irc_init_pic_handling(ps_rate_control_api->ps_pic_handling, (WORD32)u4_intra_frame_interval, i4_inter_frm_int, i4_max_inter_frm_int, i4_is_gop_closed); /*** Initialize the rate control modules ***/ if(ps_rate_control_api->e_rc_type != CONST_QP) { UWORD32 au4_num_pics_in_delay_prd[MAX_PIC_TYPE]; /* Initialize the model parameter structures */ for(i = 0; i < MAX_PIC_TYPE; i++) { irc_init_frm_rc_rd_model(ps_rate_control_api->aps_rd_model[i], MAX_FRAMES_MODELLED); } /* Initialize the buffer mechanism */ if((ps_rate_control_api->e_rc_type == VBR_STORAGE) || (ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP)) { /* Assuming both the peak bit rates are same for a VBR_STORAGE and VBR_STORAGE_DVD_COMP */ if(pu4_peak_bit_rate[0] != pu4_peak_bit_rate[1]) { trace_printf((const WORD8*)"For VBR_STORAGE and VBR_STORAGE_DVD_COMP the peak bit rates should be same\n"); } irc_init_vbr_vbv(ps_rate_control_api->ps_vbr_storage_vbv, (WORD32)pu4_peak_bit_rate[0], (WORD32)u4_frame_rate, (WORD32)u4_max_vbv_buff_size); } else if(ps_rate_control_api->e_rc_type == CBR_NLDRC) { UWORD32 u4_avg_bit_rate_copy[MAX_NUM_DRAIN_RATES]; for(i = 0; i < MAX_NUM_DRAIN_RATES; i++) { u4_avg_bit_rate_copy[i] = u4_avg_bit_rate; } /* In case of CBR the num pics in delay is ignored */ for(i = 0; i < MAX_PIC_TYPE; i++) au4_num_pics_in_delay_prd[i] = 0; irc_init_cbr_buffer(ps_rate_control_api->ps_cbr_buffer, u4_max_delay, u4_frame_rate, (WORD32 *)u4_avg_bit_rate_copy, au4_num_pics_in_delay_prd, u4_max_vbv_buff_size); } else if(ps_rate_control_api->e_rc_type == VBR_STREAMING) { irc_init_vbv_str_prms(&ps_rate_control_api->s_vbr_str_prms, u4_intra_frame_interval, u4_src_ticks, u4_tgt_ticks, u4_frms_in_delay_prd); /* Get the number of pics of each type in delay period */ irc_get_vsp_num_pics_in_dly_prd( &ps_rate_control_api->s_vbr_str_prms, au4_num_pics_in_delay_prd); irc_init_cbr_buffer(ps_rate_control_api->ps_cbr_buffer, u4_max_delay, u4_frame_rate, (WORD32 *)pu4_peak_bit_rate, au4_num_pics_in_delay_prd, u4_max_vbv_buff_size); } /* Initialize the SAD estimation module */ irc_init_est_sad(ps_rate_control_api->ps_est_sad, i4_use_est_intra_sad); /* Initialize the bit allocation module according to VBR or CBR */ if((ps_rate_control_api->e_rc_type == VBR_STORAGE) || (ps_rate_control_api->e_rc_type == VBR_STREAMING) || (ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP)) { irc_ba_init_bit_allocation(ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->ps_pic_handling, VBR_BIT_ALLOC_PERIOD, u4_avg_bit_rate, u4_frame_rate, (WORD32 *)pu4_peak_bit_rate, u4_min_bit_rate); } else if(ps_rate_control_api->e_rc_type == CBR_NLDRC) { irc_ba_init_bit_allocation(ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->ps_pic_handling, CBR_BIT_ALLOC_PERIOD, u4_avg_bit_rate, u4_frame_rate, (WORD32 *)pu4_peak_bit_rate, u4_min_bit_rate); } /* * u1_scd_detected will be initialized to 1 when a Scene change is * detected */ ps_rate_control_api->u1_scd_detected = 0; } /* Initialize the init_qp */ for(i = 0; i < MAX_PIC_TYPE; i++) { ps_rate_control_api->au1_init_qp[i] = pu1_init_qp[i]; ps_rate_control_api->au1_prev_frm_qp[i] = pu1_init_qp[i]; ps_rate_control_api->au1_min_max_qp[(i << 1)] = pu1_min_max_qp[(i << 1)]; ps_rate_control_api->au1_min_max_qp[(i << 1) + 1] = pu1_min_max_qp[(i << 1) + 1]; } /* Initialize the is_first_frm_encoded */ for(i = 0; i < MAX_PIC_TYPE; i++) { ps_rate_control_api->au1_is_first_frm_coded[i] = 0; } ps_rate_control_api->u1_is_first_frm = 1; /* * Control flag for delayed impact after a change in peak bitrate has been * made */ ps_rate_control_api->u4_frms_in_delay_prd_for_peak_bit_rate_change = 0; for(i = 0; i < MAX_NUM_DRAIN_RATES; i++) { ps_rate_control_api->au4_new_peak_bit_rate[i] = pu4_peak_bit_rate[i]; } /* Initialize the mb level rate control module */ irc_init_mb_level_rc(ps_rate_control_api->ps_mb_rate_control); ps_rate_control_api->i4_prev_frm_est_bits = u4_avg_bit_rate * 1000 / u4_frame_rate; ps_rate_control_api->prev_ref_pic_type = I_PIC; } /****************************************************************************** *Description : calls irc_add_pic_to_stack ******************************************************************************/ void irc_add_picture_to_stack(rate_control_api_t *rate_control_api, WORD32 i4_enc_pic_id) { /* Call the routine to add the pic to stack in encode order */ irc_add_pic_to_stack(rate_control_api->ps_pic_handling, i4_enc_pic_id); } void irc_add_picture_to_stack_re_enc(rate_control_api_t *rate_control_api, WORD32 i4_enc_pic_id, picture_type_e e_pic_type) { /* * In case of a re-encoder, the pics will come in the encode order itself. * So, there is no need to buffer the pics up */ irc_add_pic_to_stack_re_enc(rate_control_api->ps_pic_handling, i4_enc_pic_id, e_pic_type); } /******************************************************************************* Description : Decides the picture type based on the state ******************************************************************************/ void irc_get_picture_details(rate_control_handle rate_control_api, WORD32 *pi4_pic_id, WORD32 *pi4_pic_disp_order_no, picture_type_e *pe_pic_type) { /* Call to get the pic_details */ irc_get_pic_from_stack(rate_control_api->ps_pic_handling, pi4_pic_id, pi4_pic_disp_order_no, pe_pic_type); } /******************************************************************************* * Description : Gets the frame level qp for the given picture type ******************************************************************************/ UWORD8 irc_get_frame_level_qp(rate_control_api_t *ps_rate_control_api, picture_type_e e_pic_type, WORD32 i4_ud_max_bits) { UWORD8 u1_frame_qp, i; if((ps_rate_control_api->e_rc_type != VBR_STORAGE) && (ps_rate_control_api->e_rc_type != VBR_STORAGE_DVD_COMP) && (ps_rate_control_api->e_rc_type != CBR_NLDRC) && (ps_rate_control_api->e_rc_type != CONST_QP) && (ps_rate_control_api->e_rc_type != VBR_STREAMING)) { trace_printf((const WORD8*)(const WORD8*)" Only VBR,NLDRC and CONST QP supported for now \n"); return (0); } if(ps_rate_control_api->e_rc_type != CONST_QP) { UWORD8 u1_is_first_frm_coded = 1; /* Check whether at least one frame of a each picture type gets encoded*/ /* Check whether it is an IPP or IPB kind of encoding */ if((ps_rate_control_api->au1_is_first_frm_coded[I_PIC] && ps_rate_control_api->au1_is_first_frm_coded[P_PIC]) || ((irc_pic_type_get_intra_frame_interval( ps_rate_control_api->ps_pic_handling) == 1) && (ps_rate_control_api->au1_is_first_frm_coded[I_PIC]))) { if(e_pic_type != B_PIC) u1_is_first_frm_coded = 1; else { for(i = 0; i < MAX_PIC_TYPE; i++) { u1_is_first_frm_coded &= ps_rate_control_api->au1_is_first_frm_coded[i]; } } } else { u1_is_first_frm_coded = 0; } if(u1_is_first_frm_coded) { WORD32 i4_cur_est_texture_bits, i4_cur_est_header_bits; WORD32 i4_cur_est_bits; UWORD32 u4_estimated_sad; /* Force I frame updation of rem_bits_in_frame*/ if(irc_get_forced_I_frame_cur_frm_flag( ps_rate_control_api->ps_pic_handling) == 1) { irc_ba_change_rem_bits_in_prd_at_force_I_frame( ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->ps_pic_handling); irc_reset_forced_I_frame_cur_frm_flag( ps_rate_control_api->ps_pic_handling); } /* Get the estimated texture bits allocated for the current frame*/ i4_cur_est_texture_bits = irc_ba_get_cur_frm_est_texture_bits( ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->aps_rd_model, ps_rate_control_api->ps_est_sad, ps_rate_control_api->ps_pic_handling, e_pic_type); /* Get the estimated header bits*/ i4_cur_est_header_bits = irc_ba_get_cur_frm_est_header_bits( ps_rate_control_api->ps_bit_allocation, e_pic_type); /* Total estimated bits */ i4_cur_est_bits = i4_cur_est_header_bits + i4_cur_est_texture_bits; trace_printf((const WORD8*)"ft %d, etb = %d, eb %d, ", e_pic_type, i4_cur_est_texture_bits, i4_cur_est_bits); /* Threshold the estimated bits based on the buffer fullness*/ if(ps_rate_control_api->e_rc_type == VBR_STORAGE) { WORD32 i4_cur_frm_max_bit_possible; i4_cur_frm_max_bit_possible = irc_get_max_target_bits( ps_rate_control_api->ps_vbr_storage_vbv); if(i4_cur_est_bits > i4_cur_frm_max_bit_possible) { /* Assuming header would consume the same amount of bits */ i4_cur_est_texture_bits = i4_cur_frm_max_bit_possible - i4_cur_est_header_bits; } } else if(ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP) { WORD32 i4_rem_bits_in_gop, i4_rem_frms_in_gop, i; WORD32 i4_cur_frm_max_bit_possible, ai4_rem_frms_in_gop[MAX_PIC_TYPE]; irc_pic_type_get_rem_frms_in_gop( ps_rate_control_api->ps_pic_handling, ai4_rem_frms_in_gop); i4_rem_bits_in_gop = irc_get_rem_bits_in_period( ps_rate_control_api); i4_rem_frms_in_gop = 0; for(i = 0; i < MAX_PIC_TYPE; i++) i4_rem_frms_in_gop += ai4_rem_frms_in_gop[i]; /* Threshold the bits based on estimated buffer fullness */ i4_cur_frm_max_bit_possible = irc_get_max_tgt_bits_dvd_comp( ps_rate_control_api->ps_vbr_storage_vbv, i4_rem_bits_in_gop, i4_rem_frms_in_gop, e_pic_type); if(i4_cur_est_bits > i4_cur_frm_max_bit_possible) { /* Assuming header would consume the same amount of bits */ i4_cur_est_texture_bits = i4_cur_frm_max_bit_possible - i4_cur_est_header_bits; } } else if(ps_rate_control_api->e_rc_type == CBR_NLDRC) { WORD32 i4_cur_frm_bits_acc_buffer = irc_cbr_buffer_constraint_check( ps_rate_control_api->ps_cbr_buffer, i4_cur_est_bits, e_pic_type); /* Assuming the header would consume the same amount of bits */ i4_cur_est_texture_bits = i4_cur_frm_bits_acc_buffer - i4_cur_est_header_bits; } else if(ps_rate_control_api->e_rc_type == VBR_STREAMING) { WORD32 i4_cur_frm_bits_acc_buffer = irc_vbr_stream_buffer_constraint_check( ps_rate_control_api->ps_cbr_buffer, i4_cur_est_bits, e_pic_type); /* Assuming the header would consume the same amount of bits */ i4_cur_est_texture_bits = i4_cur_frm_bits_acc_buffer - i4_cur_est_header_bits; } trace_printf((const WORD8*)"emtb = %d, ", i4_cur_est_texture_bits); /* * If the estimated texture bits go to values less than zero * due to buffer underflow, make the estimated target bits to go * to zero */ if(i4_cur_est_texture_bits < 0) i4_cur_est_texture_bits = 0; ps_rate_control_api->i4_prev_frm_est_bits = (i4_cur_est_texture_bits + i4_cur_est_header_bits); /* Clip est_texture_bits according to the user-defined max value */ if((i4_cur_est_texture_bits > (i4_ud_max_bits - i4_cur_est_header_bits)) && (e_pic_type != I_PIC)) { i4_cur_est_texture_bits = (i4_ud_max_bits - i4_cur_est_header_bits); trace_printf((const WORD8*)"udcb = %d, ", i4_ud_max_bits - i4_cur_est_header_bits); } /* Calculate the estimated SAD for corresponding frame*/ u4_estimated_sad = irc_get_est_sad(ps_rate_control_api->ps_est_sad, e_pic_type); /* Query the model for the Qp for the corresponding frame*/ /* * The check is because the model gives a negative QP when the * i4_cur_est_texture_bits is less than or equal to 0 * [This is a bug in the model]. As a temporary fix, the frame QP * is being set to the max QP allowed */ if(i4_cur_est_texture_bits > 0) { u1_frame_qp = irc_find_qp_for_target_bits( ps_rate_control_api->aps_rd_model[e_pic_type], i4_cur_est_texture_bits, u4_estimated_sad, ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1)], ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1) + 1]); } else { u1_frame_qp = ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1) + 1]; } trace_printf((const WORD8*)"ehb %d, etb %d, fqp %d, es %d, eb %d, ", i4_cur_est_header_bits, i4_cur_est_texture_bits, u1_frame_qp, u4_estimated_sad, i4_cur_est_bits); /* Restricting the QP swing if the average bit rate has changed */ if(ps_rate_control_api->au1_avg_bitrate_changed[e_pic_type] == 0) { WORD32 prev_qp; WORD32 hi_dev_qp, lo_dev_qp; /* Restricting the qp swing */ prev_qp = ps_rate_control_api->au1_prev_frm_qp[ps_rate_control_api->prev_ref_pic_type]; if(ps_rate_control_api->prev_ref_pic_type != e_pic_type) { if(e_pic_type == I_PIC) { /* * Constrain I-frame QP to be within specified limit of * prev_ref_qp/Kp */ prev_qp = (P_TO_I_RATIO * prev_qp + (1 << (K_Q - 1))) >> (K_Q); } else if(e_pic_type == P_PIC) { /* * Constrain P-frame QP to be within specified limit of * Kp*prev_ref_qp */ prev_qp = (I_TO_P_RATIO * prev_qp + (1 << (K_Q - 1))) >> (K_Q); } else if(ps_rate_control_api->prev_ref_pic_type == P_PIC) { /* current frame is B-pic */ /* Constrain B-frame QP to be within specified limit of * prev_ref_qp/Kb */ prev_qp = (P_TO_B_RATIO * prev_qp + (1 << (K_Q - 1))) >> (K_Q); } else /* if(ps_rate_control_api->prev_ref_pic_type == I_PIC*/ { /* current frame is B-pic */ /* * Constrain B-frame QP to be within specified limit of * prev_ref_qp/Kb */ prev_qp = (P_TO_B_RATIO * I_TO_P_RATIO * prev_qp + (1 << (K_Q + K_Q - 1))) >> (K_Q + K_Q); } } /* * Due to the inexact nature of translation tables, QP may * get locked at some values. This is because of the inexactness of * the tables causing a change of +-1 in back and forth translations. * In that case, if we restrict the QP swing to +-1, we will get * the lock up condition. Hence we make it such that we will have * a swing of atleast +- 2 from prev_qp */ lo_dev_qp = GET_LO_DEV_QP(prev_qp); lo_dev_qp = MIN(lo_dev_qp, prev_qp - 2); lo_dev_qp = MAX(lo_dev_qp, ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1)]); hi_dev_qp = GET_HI_DEV_QP(prev_qp); hi_dev_qp = MAX(hi_dev_qp, prev_qp + 2); hi_dev_qp = MIN(hi_dev_qp, ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1) + 1]); u1_frame_qp = (UWORD8)CLIP_QP((WORD32)u1_frame_qp, hi_dev_qp , lo_dev_qp); } else { ps_rate_control_api->au1_avg_bitrate_changed[e_pic_type] = 0; } } else { /* * The u1_is_first_frm_coded gets reset * a) at start of sequence * b) whenever there is a scene change. * In both cases since we do not have any estimate about the * current frame, we just send in the previous frame qp value.IN * Scene change case the previous QP is incremented by 4 , This is * done because the Scene changed VOP will have over consumed and * chances of future frames skipping is very high. For the init * case, the previous frame QP is initialized with the init qp */ if((ps_rate_control_api->u1_scd_detected) && (ps_rate_control_api->e_rc_type != CONST_QP)) { /* * If scene change is detected, I frame Qp would have been * updated */ /* Use a QP calculated in the prev update fxn */ u1_frame_qp = ps_rate_control_api->u1_frm_qp_after_scd; } else { u1_frame_qp = ps_rate_control_api->au1_prev_frm_qp[e_pic_type]; } } } else { u1_frame_qp = ps_rate_control_api->au1_init_qp[e_pic_type]; } trace_printf((const WORD8*)"fqp %d\n", u1_frame_qp); return (u1_frame_qp); } /******************************************************************************* *Function Name : irc_get_buffer_status *Description : Gets the state of VBV buffer *Outputs : 0 = normal, 1 = underflow, 2= overflow *Returns : vbv_buf_status_e ******************************************************************************/ vbv_buf_status_e irc_get_buffer_status(rate_control_api_t *ps_rate_control_api, WORD32 i4_total_frame_bits, picture_type_e e_pic_type, WORD32 *pi4_num_bits_to_prevent_vbv_underflow) { vbv_buf_status_e e_buf_status = VBV_NORMAL; /* Get the buffer status for the current total consumed bits and error bits*/ if(ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP) { e_buf_status = irc_get_vbv_buffer_status( ps_rate_control_api->ps_vbr_storage_vbv, i4_total_frame_bits, pi4_num_bits_to_prevent_vbv_underflow); trace_printf((const WORD8*)"e_buf_status = %d\n", e_buf_status); } else if(ps_rate_control_api->e_rc_type == VBR_STORAGE) { /* For VBR case since there is not underflow returning the max value */ pi4_num_bits_to_prevent_vbv_underflow[0] = irc_get_max_vbv_buf_size( ps_rate_control_api->ps_vbr_storage_vbv); e_buf_status = VBV_NORMAL; } else if(ps_rate_control_api->e_rc_type == CBR_NLDRC) { e_buf_status = irc_get_cbr_buffer_status( ps_rate_control_api->ps_cbr_buffer, i4_total_frame_bits, pi4_num_bits_to_prevent_vbv_underflow, e_pic_type); } else if(ps_rate_control_api->e_rc_type == VBR_STREAMING) { /* For VBR_streaming, error bits are computed according to peak bitrate*/ e_buf_status = irc_get_cbr_buffer_status( ps_rate_control_api->ps_cbr_buffer, i4_total_frame_bits, pi4_num_bits_to_prevent_vbv_underflow, e_pic_type); } return e_buf_status; } /******************************************************************************* Function Name : irc_update_pic_handling_state Description : If the forward path and the backward path of rate control ******************************************************************************/ void irc_update_pic_handling_state(rate_control_api_t *ps_rate_control_api, picture_type_e e_pic_type) { irc_update_pic_handling(ps_rate_control_api->ps_pic_handling, e_pic_type); } /****************************************************************************** Function Name : irc_update_frame_level_info Description : Updates the frame level information into the rate control structure ******************************************************************************/ void irc_update_frame_level_info(rate_control_api_t *ps_rate_control_api, picture_type_e e_pic_type, WORD32 *pi4_mb_type_sad, WORD32 i4_total_frame_bits, WORD32 i4_model_updation_hdr_bits, WORD32 *pi4_mb_type_tex_bits, WORD32 *pi4_tot_mb_type_qp, WORD32 *pi4_tot_mb_in_type, WORD32 i4_avg_activity, UWORD8 u1_is_scd, WORD32 i4_is_it_a_skip, WORD32 i4_intra_frm_cost, WORD32 i4_is_pic_handling_done) { UWORD8 u1_num_skips = 0; WORD32 i; UWORD32 u4_frame_sad = 0; WORD32 i4_tot_texture_bits = 0; WORD32 i4_tot_mbs = 0; WORD32 i4_avg_qp = 0; /* SCD not supported in case of IPB encoder */ if(u1_is_scd && (irc_pic_type_get_inter_frame_interval( ps_rate_control_api->ps_pic_handling) > 1)) { u1_is_scd = 0; } /* For frames that contain plane areas that differ from reference frames, encoder * might generate more INTRA MBs because of lower SAD compared with INTER MBs. * Such cases should not be treated as scene change. * For such frames bits consumed will be lesser than the allocated bits. */ if(i4_total_frame_bits < ps_rate_control_api->i4_prev_frm_est_bits) { u1_is_scd = 0; } trace_printf((const WORD8*)"i4_total_frame_bits %d\n", i4_total_frame_bits); if(!i4_is_it_a_skip && !i4_is_pic_handling_done) { /* Update the pic_handling struct */ irc_update_pic_handling(ps_rate_control_api->ps_pic_handling, e_pic_type); } if(ps_rate_control_api->e_rc_type != CONST_QP) { if(!i4_is_it_a_skip) { WORD32 i4_new_period_flag; /****************************************************************** Calculate the total values from the individual values ******************************************************************/ for(i = 0; i < MAX_MB_TYPE; i++) u4_frame_sad += pi4_mb_type_sad[i]; for(i = 0; i < MAX_MB_TYPE; i++) i4_tot_texture_bits += pi4_mb_type_tex_bits[i]; for(i = 0; i < MAX_MB_TYPE; i++) i4_avg_qp += pi4_tot_mb_type_qp[i]; for(i = 0; i < MAX_MB_TYPE; i++) i4_tot_mbs += pi4_tot_mb_in_type[i]; i4_avg_qp /= i4_tot_mbs; /* Calculate the average QP */ if(ps_rate_control_api->u1_is_mb_level_rc_on) { /* * The model needs to take into consideration the average * activity of the entire frame while estimating the QP. Thus * the frame sad values are scaled by the average activity * before updating it into the model. */ if(!i4_avg_activity) i4_avg_activity = 1; i4_intra_frm_cost *= i4_avg_activity; u4_frame_sad *= i4_avg_activity; } /****************************************************************** Update the bit allocation module NOTE: For bit allocation module, the pic_type should not be modified to that of 'I', in case of a SCD. ******************************************************************/ i4_new_period_flag = irc_is_last_frame_in_gop( ps_rate_control_api->ps_pic_handling); irc_ba_update_cur_frm_consumed_bits( ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->ps_pic_handling, i4_total_frame_bits, i4_model_updation_hdr_bits, e_pic_type, u1_is_scd, i4_new_period_flag); if(1 == i4_new_period_flag && ((ps_rate_control_api->e_rc_type == VBR_STORAGE) || (ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP))) { irc_ba_check_and_update_bit_allocation( ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->ps_pic_handling, irc_get_cur_vbv_buf_size( ps_rate_control_api->ps_vbr_storage_vbv), irc_get_max_vbv_buf_size( ps_rate_control_api->ps_vbr_storage_vbv), irc_get_max_bits_per_tgt_frm( ps_rate_control_api->ps_vbr_storage_vbv), i4_total_frame_bits); } } /********************************************************************** Update the buffer status *********************************************************************/ /* * This update is done after overflow and underflow handling to * account for the actual bits dumped */ if((ps_rate_control_api->e_rc_type == VBR_STORAGE) || (ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP)) { irc_update_vbr_vbv(ps_rate_control_api->ps_vbr_storage_vbv, i4_total_frame_bits); } else if(ps_rate_control_api->e_rc_type == CBR_NLDRC) { irc_update_cbr_buffer(ps_rate_control_api->ps_cbr_buffer, i4_total_frame_bits, e_pic_type); } else if(ps_rate_control_api->e_rc_type == VBR_STREAMING) { UWORD32 au4_num_pics_in_delay_prd[MAX_PIC_TYPE]; irc_get_vsp_num_pics_in_dly_prd( &ps_rate_control_api->s_vbr_str_prms, au4_num_pics_in_delay_prd); irc_update_cbr_buffer(ps_rate_control_api->ps_cbr_buffer, i4_total_frame_bits, e_pic_type); irc_update_vbr_str_prms(&ps_rate_control_api->s_vbr_str_prms, e_pic_type); irc_change_cbr_vbv_num_pics_in_delay_period( ps_rate_control_api->ps_cbr_buffer, au4_num_pics_in_delay_prd); /* * If the change_in_peak_bitrate flag is set, after the delay period * update the peak_bitrate and the buffer parameters */ if(!ps_rate_control_api->u4_frms_in_delay_prd_for_peak_bit_rate_change) { irc_ba_change_ba_peak_bit_rate( ps_rate_control_api->ps_bit_allocation, (WORD32 *)&ps_rate_control_api->au4_new_peak_bit_rate[0]); irc_change_cbr_vbv_bit_rate( ps_rate_control_api->ps_cbr_buffer, (WORD32 *)&ps_rate_control_api->au4_new_peak_bit_rate[0]); } if(ps_rate_control_api->u4_frms_in_delay_prd_for_peak_bit_rate_change) ps_rate_control_api->u4_frms_in_delay_prd_for_peak_bit_rate_change--; } if(!i4_is_it_a_skip) { /******************************************************************* Handle the SCENE CHANGE DETECTED 1) Make the picture type as I, so that updation happens as if it is an I frame 2) Reset model, SAD and flag to restart the estimation process ******************************************************************/ if(u1_is_scd) { WORD32 i4_frm_qp_after_scd; UWORD32 u4_prev_I_frm_sad; e_pic_type = I_PIC; /* Scale scd qp based on SCD Frm sad and previous I Frm sad */ /* frm_qp_after_scd = (avg_qp * cur_frm_sad)/prev_I_frm_sad */ /* * QP for the next frame should take care of * 1) due to scene change, the current picture has consumed more * bits * 2) relative complexity of the previous scene and the current * scene */ /* Get the intra SAD for the previous scene */ u4_prev_I_frm_sad = irc_get_est_sad( ps_rate_control_api->ps_est_sad, I_PIC); /* * Scale the QP based on the SAD ratio of the current pic and * previous scene intra SAD */ X_PROD_Y_DIV_Z(i4_avg_qp, u4_frame_sad, u4_prev_I_frm_sad, i4_frm_qp_after_scd); /* Limit the next frame qp by 50% across both the sides */ if(i4_frm_qp_after_scd > ((i4_avg_qp * 3) >> 1)) { i4_frm_qp_after_scd = (i4_avg_qp * 3) >> 1; } else if(i4_frm_qp_after_scd < (i4_avg_qp >> 1)) { i4_frm_qp_after_scd = (i4_avg_qp >> 1); } /* * Ensure that the next frame QP is within the min_max limit of * QP allowed */ if(i4_frm_qp_after_scd > ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1) + 1]) { i4_frm_qp_after_scd = ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1) + 1]; } else if(i4_frm_qp_after_scd < ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1)]) { i4_frm_qp_after_scd = ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1)]; } /* Update the state var */ ps_rate_control_api->u1_frm_qp_after_scd = (UWORD8)i4_frm_qp_after_scd; /* re-set model */ for(i = 0; i < MAX_PIC_TYPE; i++) { irc_reset_frm_rc_rd_model( ps_rate_control_api->aps_rd_model[i]); } /* Reset the SAD estimation module */ irc_reset_est_sad(ps_rate_control_api->ps_est_sad); /* Reset flag */ for(i = 0; i < MAX_PIC_TYPE; i++) { ps_rate_control_api->au1_is_first_frm_coded[i] = 0; } /* Reset the MB Rate control */ irc_init_mb_level_rc(ps_rate_control_api->ps_mb_rate_control); /*Set u1_scd_detected flag*/ ps_rate_control_api->u1_scd_detected = 1; /* * Adjust the average QP for the frame based on bits * consumption */ /* * Initialize the QP for each picture type according to the * average QP of the SCD pic */ ps_rate_control_api->au1_prev_frm_qp[I_PIC] = (UWORD8)i4_avg_qp; trace_printf((const WORD8*)"SCD DETECTED\n"); } else { ps_rate_control_api->u1_scd_detected = 0; /************************************************************** Update the Qp used by the current frame **************************************************************/ ps_rate_control_api->au1_prev_frm_qp[e_pic_type] = (UWORD8)i4_avg_qp; } /******************************************************************** Update the model of the correponding picture type NOTE: For SCD, we force the frame type from 'P' to that of a 'I' ******************************************************************/ /* * For very simple sequences no bits are consumed by texture. These * frames do not add any information to the model and so not added */ if(i4_tot_texture_bits && u4_frame_sad) { irc_add_frame_to_rd_model( ps_rate_control_api->aps_rd_model[e_pic_type], i4_tot_texture_bits, (UWORD8)i4_avg_qp, u4_frame_sad, u1_num_skips); /* * At least one proper frame in added into the model. Until that * keep using the initial QP */ ps_rate_control_api->au1_is_first_frm_coded[e_pic_type] = 1; } if(i4_avg_activity) { /* Update the mb_level model */ irc_mb_update_frame_level( ps_rate_control_api->ps_mb_rate_control, i4_avg_activity); } /****************************************************************** Update the sad estimation module NOTE: For SCD, we force the frame type from 'P' to that of a 'I' ******************************************************************/ if(u4_frame_sad) { irc_update_actual_sad(ps_rate_control_api->ps_est_sad, u4_frame_sad, e_pic_type); irc_update_actual_sad_for_intra(ps_rate_control_api->ps_est_sad, i4_intra_frm_cost); } /* * Update the variable which denotes that a frame has been * encountered */ ps_rate_control_api->u1_is_first_frm = 0; } } /* Store the prev encoded picture type for restricting Qp swing */ if((e_pic_type == I_PIC) || (e_pic_type == P_PIC)) { ps_rate_control_api->prev_ref_pic_type = e_pic_type; } trace_printf((const WORD8*)"ft %d,hb %d,tb %d,qp %d,fs %d\n", e_pic_type, i4_model_updation_hdr_bits, i4_tot_texture_bits, i4_avg_qp, u4_frame_sad); return; } /******************************************************************************* MB Level API functions ******************************************************************************/ /****************************************************************************** Function Name : irc_init_mb_rc_frame_level Description : Initialise the frame level details required for a mb level ******************************************************************************/ void irc_init_mb_rc_frame_level(rate_control_api_t *ps_rate_control_api, UWORD8 u1_frame_qp) { irc_mb_init_frame_level(ps_rate_control_api->ps_mb_rate_control, u1_frame_qp); } /****************************************************************************** Function Name : irc_get_mb_level_qp Description : Get the mb level qp *****************************************************************************/ void irc_get_mb_level_qp(rate_control_api_t *ps_rate_control_api, WORD32 i4_cur_mb_activity, WORD32 *pi4_mb_qp, picture_type_e e_pic_type) { if(ps_rate_control_api->u1_is_mb_level_rc_on) { irc_get_mb_qp(ps_rate_control_api->ps_mb_rate_control, i4_cur_mb_activity, pi4_mb_qp); /* Truncating the QP to the Max and Min Qp values possible */ if(pi4_mb_qp[1] < ps_rate_control_api->au1_min_max_qp[e_pic_type << 1]) { pi4_mb_qp[1] = ps_rate_control_api->au1_min_max_qp[e_pic_type << 1]; } if(pi4_mb_qp[1] > ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1) + 1]) { pi4_mb_qp[1] = ps_rate_control_api->au1_min_max_qp[(e_pic_type << 1) + 1]; } } else { WORD32 i4_qp; i4_qp = irc_get_frm_level_qp(ps_rate_control_api->ps_mb_rate_control); /* Both the qp are used for */ pi4_mb_qp[0] = i4_qp; /* Used as feedback for the rate control */ pi4_mb_qp[1] = i4_qp; /* Used for quantising the MB*/ } } /**************************************************************************** Function Name : irc_get_bits_to_stuff Description : Gets the bits to stuff to prevent Underflow of Encoder Buffer *****************************************************************************/ WORD32 irc_get_bits_to_stuff(rate_control_api_t *ps_rate_control_api, WORD32 i4_tot_consumed_bits, picture_type_e e_pic_type) { WORD32 i4_bits_to_stuff; /* Get the CBR bits to stuff*/ i4_bits_to_stuff = irc_get_cbr_bits_to_stuff( ps_rate_control_api->ps_cbr_buffer, i4_tot_consumed_bits, e_pic_type); return i4_bits_to_stuff; } /**************************************************************************** Function Name : irc_get_prev_frm_est_bits Description : Returns previous frame estimated bits *****************************************************************************/ WORD32 irc_get_prev_frm_est_bits(rate_control_api_t *ps_rate_control_api) { return (ps_rate_control_api->i4_prev_frm_est_bits); } /****************************************************************************** Control Level API functions Logic: The control call sets the state structure of the rate control api accordingly such that the next process call would implement the same. ******************************************************************************/ void irc_change_inter_frm_int_call(rate_control_api_t *ps_rate_control_api, WORD32 i4_inter_frm_int) { irc_pic_handling_register_new_inter_frm_interval( ps_rate_control_api->ps_pic_handling, i4_inter_frm_int); } void irc_change_intra_frm_int_call(rate_control_api_t *ps_rate_control_api, WORD32 i4_intra_frm_int) { irc_pic_handling_register_new_int_frm_interval( ps_rate_control_api->ps_pic_handling, i4_intra_frm_int); if(ps_rate_control_api->e_rc_type == VBR_STREAMING) { irc_change_vsp_ifi(&ps_rate_control_api->s_vbr_str_prms, i4_intra_frm_int); } } /**************************************************************************** Function Name : irc_change_avg_bit_rate Description : Whenever the average bit rate changes, the excess bits is between the changed bit rate and the old one is re-distributed in the bit allocation module *****************************************************************************/ void irc_change_avg_bit_rate(rate_control_api_t *ps_rate_control_api, UWORD32 u4_average_bit_rate) { int i; if(ps_rate_control_api->e_rc_type != CONST_QP) { /* * Bit Allocation Module: distribute the excess/deficit bits between the * old and the new frame rate to all the remaining frames */ irc_ba_change_remaining_bits_in_period( ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->ps_pic_handling, u4_average_bit_rate, irc_ba_get_frame_rate( ps_rate_control_api->ps_bit_allocation), (WORD32 *)(ps_rate_control_api->au4_new_peak_bit_rate)); } if(ps_rate_control_api->e_rc_type == CBR_NLDRC) { UWORD32 u4_average_bit_rate_copy[MAX_NUM_DRAIN_RATES]; for(i = 0; i < MAX_NUM_DRAIN_RATES; i++) { u4_average_bit_rate_copy[i] = u4_average_bit_rate; } irc_change_cbr_vbv_bit_rate(ps_rate_control_api->ps_cbr_buffer, (WORD32 *)(u4_average_bit_rate_copy)); } /* * This is done only for average bitrate changing somewhere after the model * stabilizes.Here it is assumed that user will not do this call after * first few frames. If we dont have this check, what would happen is since * the model has not stabilized, also bitrate has changed before the first * frame, we dont restrict the qp. Qp can go to very bad values after init * qp since if swing is disabled. * This check will become buggy if change bitrate is called say somewhere * after first two frames.Bottom line - RC init is done during create and * this call is done just before first process.And we want to differentiate * between this call done before first process and the call which is done * during run time */ if(ps_rate_control_api->u1_is_first_frm == 0) { for(i = 0; i < MAX_PIC_TYPE; i++) { ps_rate_control_api->au1_avg_bitrate_changed[i] = 1; } } } /**************************************************************************** Function Name : irc_change_frame_rate Description : Does the necessary changes whenever there is a change in frame rate *****************************************************************************/ void irc_change_frame_rate(rate_control_api_t *ps_rate_control_api, UWORD32 u4_frame_rate, UWORD32 u4_src_ticks, UWORD32 u4_tgt_ticks) { if(ps_rate_control_api->e_rc_type != CONST_QP) { UWORD32 u4_frms_in_delay_prd = ((u4_frame_rate * irc_get_cbr_buffer_delay( ps_rate_control_api->ps_cbr_buffer)) / 1000000); if((ps_rate_control_api->e_rc_type == VBR_STORAGE) || (ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP)) { irc_change_vbr_vbv_frame_rate( ps_rate_control_api->ps_vbr_storage_vbv, u4_frame_rate); } else if(ps_rate_control_api->e_rc_type == CBR_NLDRC) { irc_change_cbr_vbv_tgt_frame_rate( ps_rate_control_api->ps_cbr_buffer, u4_frame_rate); } else if(ps_rate_control_api->e_rc_type == VBR_STREAMING) { UWORD32 au4_num_pics_in_delay_prd[MAX_PIC_TYPE]; irc_change_vsp_tgt_ticks(&ps_rate_control_api->s_vbr_str_prms, u4_tgt_ticks); irc_change_vsp_src_ticks(&ps_rate_control_api->s_vbr_str_prms, u4_src_ticks); irc_change_vsp_fidp(&ps_rate_control_api->s_vbr_str_prms, u4_frms_in_delay_prd); irc_get_vsp_num_pics_in_dly_prd( &ps_rate_control_api->s_vbr_str_prms, au4_num_pics_in_delay_prd); irc_change_cbr_vbv_tgt_frame_rate( ps_rate_control_api->ps_cbr_buffer, u4_frame_rate); irc_change_cbr_vbv_num_pics_in_delay_period( ps_rate_control_api->ps_cbr_buffer, au4_num_pics_in_delay_prd); } /* * Bit Allocation Module: distribute the excess/deficit bits between the * old and the new frame rate to all the remaining frames */ irc_ba_change_remaining_bits_in_period( ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->ps_pic_handling, irc_ba_get_bit_rate( ps_rate_control_api->ps_bit_allocation), u4_frame_rate, (WORD32 *)(ps_rate_control_api->au4_new_peak_bit_rate)); } } /**************************************************************************** Function Name : irc_change_frm_rate_for_bit_alloc Description : Does the necessary changes only in the bit_allocation module there is a change in frame rate *****************************************************************************/ void irc_change_frm_rate_for_bit_alloc(rate_control_api_t *ps_rate_control_api, UWORD32 u4_frame_rate) { if(ps_rate_control_api->e_rc_type != CONST_QP) { /* * Bit Allocation Module: distribute the excess/deficit bits between the * old and the new frame rate to all the remaining frames */ irc_ba_change_remaining_bits_in_period( ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->ps_pic_handling, irc_ba_get_bit_rate( ps_rate_control_api->ps_bit_allocation), u4_frame_rate, (WORD32 *)(ps_rate_control_api->au4_new_peak_bit_rate)); if(ps_rate_control_api->e_rc_type == VBR_STORAGE || ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP) { irc_change_vbr_max_bits_per_tgt_frm( ps_rate_control_api->ps_vbr_storage_vbv, u4_frame_rate); } } } void irc_change_init_qp(rate_control_api_t *ps_rate_control_api, UWORD8 *pu1_init_qp) { WORD32 i; /* Initialize the init_qp */ for(i = 0; i < MAX_PIC_TYPE; i++) { ps_rate_control_api->au1_init_qp[i] = pu1_init_qp[i]; ps_rate_control_api->au1_prev_frm_qp[i] = pu1_init_qp[i]; } } void irc_change_min_max_qp(rate_control_api_t *ps_rate_control_api, UWORD8 *pu1_min_max_qp) { WORD32 i; for(i = 0; i < MAX_PIC_TYPE; i++) { ps_rate_control_api->au1_min_max_qp[(i << 1)] = pu1_min_max_qp[(i << 1)]; ps_rate_control_api->au1_min_max_qp[(i << 1) + 1] = pu1_min_max_qp[(i << 1) + 1]; } } /**************************************************************************** Function Name : irc_change_peak_bit_rate Description : Does the necessary changes whenever there is a change in peak bit rate *****************************************************************************/ WORD32 irc_change_peak_bit_rate(rate_control_api_t *ps_rate_control_api, UWORD32 *pu4_peak_bit_rate) { WORD32 i4_ret_val = RC_OK; int i; /* * Buffer Mechanism Module: Re-initialize the number of bits consumed per * frame */ if(ps_rate_control_api->e_rc_type == VBR_STORAGE || ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP) { /* Send the new peak bit rate and the old frame rate */ irc_change_vbr_vbv_bit_rate(ps_rate_control_api->ps_vbr_storage_vbv, pu4_peak_bit_rate[0]); irc_ba_change_ba_peak_bit_rate(ps_rate_control_api->ps_bit_allocation, (WORD32 *)pu4_peak_bit_rate); for(i = 0; i < MAX_NUM_DRAIN_RATES; i++) { ps_rate_control_api->au4_new_peak_bit_rate[i] = pu4_peak_bit_rate[i]; } } else if(ps_rate_control_api->e_rc_type == VBR_STREAMING) { if(ps_rate_control_api->u4_frms_in_delay_prd_for_peak_bit_rate_change) { /* * Means that change in peak bit rate has been made twice before the * previous change could take effect */ i4_ret_val = RC_BENIGN_ERR; } /* * If the change happens before encoding the first frame make the * effect immediately else delay the effect */ if(ps_rate_control_api->u1_is_first_frm) { for(i = 0; i < MAX_NUM_DRAIN_RATES; i++) { ps_rate_control_api->au4_new_peak_bit_rate[i] = pu4_peak_bit_rate[i]; } irc_ba_change_ba_peak_bit_rate( ps_rate_control_api->ps_bit_allocation, (WORD32 *)pu4_peak_bit_rate); irc_change_cbr_vbv_bit_rate(ps_rate_control_api->ps_cbr_buffer, (WORD32 *)pu4_peak_bit_rate); } else { UWORD32 au4_num_pics_in_delay_prd[MAX_NUM_DRAIN_RATES]; /* * Else store the number of frames after which the effect should * happen and then update the peak bitrate */ ps_rate_control_api->u4_frms_in_delay_prd_for_peak_bit_rate_change = irc_get_vsp_num_pics_in_dly_prd( &ps_rate_control_api->s_vbr_str_prms, au4_num_pics_in_delay_prd); for(i = 0; i < MAX_NUM_DRAIN_RATES; i++) { ps_rate_control_api->au4_new_peak_bit_rate[i] = pu4_peak_bit_rate[i]; } } } return (i4_ret_val); } void irc_change_buffer_delay(rate_control_api_t *ps_rate_control_api, UWORD32 u4_buffer_delay) { UWORD32 u4_frms_in_delay_prd = ((irc_ba_get_frame_rate( ps_rate_control_api->ps_bit_allocation) * u4_buffer_delay) / 1000000); /* Initialize the rate control modules */ if(ps_rate_control_api->e_rc_type == CBR_NLDRC) { irc_change_cbr_buffer_delay(ps_rate_control_api->ps_cbr_buffer, u4_buffer_delay); } else if(ps_rate_control_api->e_rc_type == VBR_STORAGE || ps_rate_control_api->e_rc_type == VBR_STORAGE_DVD_COMP) { UWORD32 au4_num_pics_in_delay_prd[MAX_PIC_TYPE]; irc_change_vsp_fidp(&ps_rate_control_api->s_vbr_str_prms, u4_frms_in_delay_prd); /* Get the number of pics of each type in delay period */ irc_get_vsp_num_pics_in_dly_prd(&ps_rate_control_api->s_vbr_str_prms, au4_num_pics_in_delay_prd); irc_change_cbr_vbv_num_pics_in_delay_period( ps_rate_control_api->ps_cbr_buffer, au4_num_pics_in_delay_prd); } } /* Getter functions to get the current rate control parameters */ UWORD32 irc_get_frame_rate(rate_control_api_t *ps_rate_control_api) { return (irc_ba_get_frame_rate(ps_rate_control_api->ps_bit_allocation)); } UWORD32 irc_get_bit_rate(rate_control_api_t *ps_rate_control_api) { return (irc_ba_get_bit_rate(ps_rate_control_api->ps_bit_allocation)); } UWORD32 irc_get_peak_bit_rate(rate_control_api_t *ps_rate_control_api, WORD32 i4_index) { return (ps_rate_control_api->au4_new_peak_bit_rate[i4_index]); } UWORD32 irc_get_intra_frame_interval(rate_control_api_t *ps_rate_control_api) { return (irc_pic_type_get_intra_frame_interval( ps_rate_control_api->ps_pic_handling)); } UWORD32 irc_get_inter_frame_interval(rate_control_api_t *ps_rate_control_api) { return (irc_pic_type_get_inter_frame_interval( ps_rate_control_api->ps_pic_handling)); } rc_type_e irc_get_rc_type(rate_control_api_t *ps_rate_control_api) { return (ps_rate_control_api->e_rc_type); } WORD32 irc_get_bits_per_frame(rate_control_api_t *ps_rate_control_api) { WORD32 i4_bits_per_frm; X_PROD_Y_DIV_Z(irc_ba_get_bit_rate(ps_rate_control_api->ps_bit_allocation), (UWORD32)1000, irc_ba_get_frame_rate(ps_rate_control_api->ps_bit_allocation), i4_bits_per_frm); return (i4_bits_per_frm); } UWORD32 irc_get_max_delay(rate_control_api_t *ps_rate_control_api) { return (irc_get_cbr_buffer_delay(ps_rate_control_api->ps_cbr_buffer)); } UWORD32 irc_get_seq_no(rate_control_api_t *ps_rate_control_api) { return (irc_pic_type_get_disp_order_no(ps_rate_control_api->ps_pic_handling)); } UWORD32 irc_get_rem_frames_in_gop(rate_control_api_t *ps_rate_control_api) { WORD32 ai4_rem_frms_in_period[MAX_PIC_TYPE]; WORD32 j; UWORD32 u4_rem_frms_in_period = 0; /* Get the rem_frms_in_gop & the frms_in_gop from the pic_type state struct */ irc_pic_type_get_rem_frms_in_gop(ps_rate_control_api->ps_pic_handling, ai4_rem_frms_in_period); /* Depending on the number of gops in a period, find the num_frms_in_prd */ for(j = 0; j < MAX_PIC_TYPE; j++) { u4_rem_frms_in_period += ai4_rem_frms_in_period[j]; } return (u4_rem_frms_in_period); } /**************************************************************************** Function Name : irc_flush_buf_frames Description : API call to flush the buffered up frames *****************************************************************************/ void irc_flush_buf_frames(rate_control_api_t *ps_rate_control_api) { irc_flush_frame_from_pic_stack(ps_rate_control_api->ps_pic_handling); } /**************************************************************************** Function Name : irc_flush_buf_frames Description : API call to flush the buffered up frames *****************************************************************************/ void irc_post_encode_frame_skip(rate_control_api_t *ps_rate_control_api, picture_type_e e_pic_type) { irc_skip_encoded_frame(ps_rate_control_api->ps_pic_handling, e_pic_type); } /**************************************************************************** Function Name : irc_force_I_frame Description : API call to force an I frame *****************************************************************************/ void irc_force_I_frame(rate_control_api_t *ps_rate_control_api) { irc_set_force_I_frame_flag(ps_rate_control_api->ps_pic_handling); } /**************************************************************************** * Function Name : rc_get_rem_bits_in_gop * Description : API call to get remaining bits in GOP * *****************************************************************************/ WORD32 irc_get_rem_bits_in_period(rate_control_api_t *ps_rate_control_api) { return (irc_ba_get_rem_bits_in_period( ps_rate_control_api->ps_bit_allocation, ps_rate_control_api->ps_pic_handling)); } /**************************************************************************** * Function Name : irc_get_vbv_buf_fullness * Description : API call to get VBV buffer fullness ******************************************************************************/ WORD32 irc_get_vbv_buf_fullness(rate_control_api_t *ps_rate_control_api) { return (irc_get_cur_vbv_buf_size(ps_rate_control_api->ps_vbr_storage_vbv)); } WORD32 irc_get_vbv_buf_size(rate_control_api_t *ps_rate_control_api) { if(ps_rate_control_api->e_rc_type == CBR_NLDRC || ps_rate_control_api->e_rc_type == VBR_STREAMING) { return (irc_get_cbr_buffer_size(ps_rate_control_api->ps_cbr_buffer)); } else { return (irc_get_max_vbv_buf_size( ps_rate_control_api->ps_vbr_storage_vbv)); } } WORD32 irc_get_vbv_fulness_with_cur_bits(rate_control_api_t *ps_rate_control_api, UWORD32 u4_bits) { return (irc_vbv_get_vbv_buf_fullness( ps_rate_control_api->ps_vbr_storage_vbv, u4_bits)); } void irc_set_avg_mb_act(rate_control_api_t *ps_rate_control_api, WORD32 i4_avg_activity) { irc_mb_update_frame_level(ps_rate_control_api->ps_mb_rate_control, i4_avg_activity); return; }