libavc/encoder/irc_rate_control_api.c
Ram Mohan M 50fd862b8d libavcenc: Remove duplicate code and improve readability
This commit does not introduce any new functionality w.r.t previous
commit. But it fixes few things. They are listed below:
1. Guard Bands in header files are fixed
2. Header files contains function definition comments. These are same
as in source file. Maintaining same comment at two locations is
unnecessary. These are removed.
3. Improved consistency and code indentation
4. Removed comments that dont align with implementation
5. Grouped headers of a workspace together
2023-10-01 01:37:17 +05:30

1690 lines
70 KiB
C

/******************************************************************************
*
* 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)))
/*****************************************************************************
Function Name : fill_memtab
Description : fill memtab
Inputs :
ps_mem_tab - Memtab pointer
u4_size - Size of the memtab
i4_alignment - alignment of the memtab
e_usage - usage
e_mem_region - region
*****************************************************************************/
void fill_memtab(itt_memtab_t *ps_mem_tab,
WORD32 u4_size,
WORD32 i4_alignment,
ITT_MEM_USAGE_TYPE_E e_usage,
ITT_MEM_REGION_E e_mem_region)
{
/* Make the size next multiple of alignment */
WORD32 i4_aligned_size = (((u4_size) + (i4_alignment-1)) & (~(i4_alignment-1)));
/* Fill the memtab */
ps_mem_tab->u4_size = i4_aligned_size;
ps_mem_tab->i4_alignment = i4_alignment;
ps_mem_tab->e_usage = e_usage;
ps_mem_tab->e_mem_region = e_mem_region;
}
/*****************************************************************************
Function Name : use_or_fill_base
Description : Get or Set base pointer for the memtab
Inputs :
ps_mem_tab - Memtab pointer
ptr_to_be_filled - Pointer to base pointer
e_func_type - Get/Set flag
*****************************************************************************/
WORD32 use_or_fill_base(itt_memtab_t *ps_mem_tab,
void **ptr_to_be_filled,
ITT_FUNC_TYPE_E e_func_type)
{
/* Fill base for freeing the allocated memory */
if (e_func_type == FILL_BASE)
{
if (ptr_to_be_filled[0] != 0)
{
ps_mem_tab->pv_base = ptr_to_be_filled[0];
return (0);
}
else
{
return (-1);
}
}
/* obtain the allocated memory from base pointer */
if (e_func_type == USE_BASE)
{
if (ps_mem_tab->pv_base != 0)
{
ptr_to_be_filled[0] = ps_mem_tab->pv_base;
return (0);
}
else
{
return (-1);
}
}
return (0);
}
/*****************************************************************************/
/* 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;
X_PROD_Y_DIV_Z(u4_frame_rate, u4_max_delay, 1000000, u4_frms_in_delay_prd);
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);
X_PROD_Y_DIV_Z(u4_avg_bit_rate, 1000, u4_frame_rate,
ps_rate_control_api->i4_prev_frm_est_bits);
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;
}