/******************************************************************************
*
* 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;
}