aosp12/external/libhevc/encoder/ihevce_rc_interface.c

5958 lines
233 KiB
C

/******************************************************************************
*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*****************************************************************************
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
/**
******************************************************************************
* @file ihevce_rc_interface.c
*
* @brief
* This file contains function definitions for rc api interface
*
* @author
* Ittiam
*
* List of Functions
* <TODO: Update this>
*
******************************************************************************
*/
/*****************************************************************************/
/* File Includes */
/*****************************************************************************/
/* System include files */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>
#include <math.h>
/* User include files */
#include "ihevc_typedefs.h"
#include "itt_video_api.h"
#include "ihevce_api.h"
#include "rc_cntrl_param.h"
#include "rc_frame_info_collector.h"
#include "rc_look_ahead_params.h"
#include "mem_req_and_acq.h"
#include "rate_control_api.h"
#include "var_q_operator.h"
#include "ihevc_defs.h"
#include "ihevc_debug.h"
#include "ihevc_macros.h"
#include "ihevc_structs.h"
#include "ihevc_platform_macros.h"
#include "ihevc_deblk.h"
#include "ihevc_itrans_recon.h"
#include "ihevc_chroma_itrans_recon.h"
#include "ihevc_chroma_intra_pred.h"
#include "ihevc_intra_pred.h"
#include "ihevc_inter_pred.h"
#include "ihevc_mem_fns.h"
#include "ihevc_padding.h"
#include "ihevc_weighted_pred.h"
#include "ihevc_sao.h"
#include "ihevc_resi_trans.h"
#include "ihevc_quant_iquant_ssd.h"
#include "ihevce_defs.h"
#include "ihevce_hle_interface.h"
#include "ihevce_lap_enc_structs.h"
#include "ihevce_lap_interface.h"
#include "ihevce_multi_thrd_structs.h"
#include "ihevce_me_common_defs.h"
#include "ihevce_had_satd.h"
#include "ihevce_function_selector.h"
#include "ihevce_enc_structs.h"
#include "ihevce_cmn_utils_instr_set_router.h"
#include "hme_datatype.h"
#include "hme_interface.h"
#include "hme_common_defs.h"
#include "hme_defs.h"
#include "ihevce_rc_enc_structs.h"
#include "ihevce_rc_structs.h"
#include "ihevce_rc_interface.h"
#include "ihevce_frame_process_utils.h"
/*****************************************************************************/
/* Constant Macros */
/*****************************************************************************/
#define USE_USER_FIRST_FRAME_QP 0
#define DEBUG_PRINT 0
#define DETERMINISTIC_RC 1
#define USE_QP_OFFSET_POST_SCD 1
#define USE_SQRT 0
#define K_SCALING_FACTOR 8
#define ENABLE_2_PASS_BIT_ALLOC_FRM_1ST 0
#define VBV_THRSH_I_PIC_DELTA_QP_1 (0.85)
#define VBV_THRSH_I_PIC_DELTA_QP_2 (0.75)
#define VBV_THRSH_P_PIC_DELTA_QP_1 (0.80)
#define VBV_THRSH_P_PIC_DELTA_QP_2 (0.70)
#define VBV_THRSH_BR_PIC_DELTA_QP_1 (0.75)
#define VBV_THRSH_BR_PIC_DELTA_QP_2 (0.65)
#define VBV_THRSH_BNR_PIC_DELTA_QP_1 (0.75)
#define VBV_THRSH_BNR_PIC_DELTA_QP_2 (0.65)
#define VBV_THRSH_DELTA_QP (0.6)
#define VBV_THRSH_FRM_PRLL_I_PIC_DELTA_QP_1 (0.70)
#define VBV_THRSH_FRM_PRLL_I_PIC_DELTA_QP_2 (0.60)
#define VBV_THRSH_FRM_PRLL_P_PIC_DELTA_QP_1 (0.65)
#define VBV_THRSH_FRM_PRLL_P_PIC_DELTA_QP_2 (0.55)
#define VBV_THRSH_FRM_PRLL_BR_PIC_DELTA_QP_1 (0.60)
#define VBV_THRSH_FRM_PRLL_BR_PIC_DELTA_QP_2 (0.50)
#define VBV_THRSH_FRM_PRLL_BNR_PIC_DELTA_QP_1 (0.60)
#define VBV_THRSH_FRM_PRLL_BNR_PIC_DELTA_QP_2 (0.50)
#define VBV_THRSH_FRM_PRLL_DELTA_QP (0.45)
#define TRACE_SUPPORT 0
/*****************************************************************************/
/* Globals */
/*****************************************************************************/
/*
Modified bpp vs nor satd/act/qp :
=================================
Prestine Quality
-----------------
480p y = -0.1331x3 - 0.0589x2 + 2.5091x - 0.0626
720p y = -0.3603x3 + 0.4504x2 + 2.2056x - 0.0411
1080p y = -0.7085x3 + 0.9743x2 + 1.939x - 0.0238
2160p y = -1.2447x3 + 2.1218x2 + 1.4995x - 0.0108
High Quality
-------------
480p y = -0.1348x3 - 0.0557x2 + 2.5055x - 0.0655
720p y = -0.0811x3 + 0.1988x2 + 1.246x - 0.0385
1080p y = -0.74x3 + 1.0552x2 + 1.8942x - 0.0251
2160p y = -1.3851x3 + 2.3372x2 + 1.4255x - 0.0113
Medium Speed
-------------
480p y = -0.143x3 - 0.0452x2 + 2.5581x - 0.0765
720p y = -0.3997x3 + 0.542x2 + 2.201x - 0.0507
1080p y = -0.816x3 + 1.2048x2 + 1.8689x - 0.0298
2160p y = -1.5169x3 + 2.5857x2 + 1.3478x - 0.0126
High Speed
-----------
480p y = -0.1472x3 - 0.0341x2 + 2.5605x - 0.0755
720p y = -0.3967x3 + 0.526x2 + 2.2228x - 0.0504
1080p y = -0.8008x3 + 1.1713x2 + 1.8897x - 0.0297
2160p y = -1.503x3 + 2.576x2 + 1.3476x - 0.0123
Extreme Speed
--------------
480p y = -0.1379x3 - 0.059x2 + 2.5716x - 0.0756
720p y = -0.3938x3 + 0.521x2 + 2.2239x - 0.0505
1080p y = -0.8041x3 + 1.1725x2 + 1.8874x - 0.0293
2160p y = -1.4863x3 + 2.556x2 + 1.344x - 0.0122
*/
const double g_offline_i_model_coeff[20][4] = {
/*ultra_HD*/
{ -1.2447, 2.1218, 1.4995, -0.0108 }, /*Prestine quality*/
{ -1.3851, 2.3372, 1.4255, -0.0113 }, /*High quality*/
{ -1.5169, 2.5857, 1.3478, -0.0126 }, /*Medium speed*/
{ -1.503, 2.576, 1.3476, -0.0123 }, /*high speed*/
{ -1.4863, 2.556, 1.344, -0.0122 }, /*Extreme Speed*/
/*Full HD*/
{ -0.7085, 0.9743, 1.939, -0.0238 }, /*Prestine quality*/
{ -0.74, 1.0552, 1.8942, -0.0251 }, /*High quality*/
{ -0.816, 1.2048, 1.8689, -0.0298 }, /*Medium speed*/
{ -0.8008, 1.1713, 1.8897, -0.0297 }, /*high speed*/
{ -0.8041, 1.1725, 1.8874, -0.0293 }, /*Extreme Speed*/
/*720p*/
{ -0.3603, 0.4504, 2.2056, -0.0411 }, /*Prestine quality*/
// {-0.0811, 0.1988, 1.246, - 0.0385},/*High quality*/
{ -0.3997, 0.542, 2.201, -0.0507 },
{ -0.3997, 0.542, 2.201, -0.0507 }, /*Medium speed*/
{ -0.3967, 0.526, 2.2228, -0.0504 }, /*high speed*/
{ -0.3938, 0.521, 2.2239, -0.0505 }, /*Extreme Speed*/
/*SD*/
{ -0.1331, -0.0589, 2.5091, -0.0626 }, /*Prestine quality*/
{ -0.1348, -0.0557, 2.5055, -0.0655 }, /*High quality*/
{ -0.143, -0.0452, 2.5581, -0.0765 }, /*Medium speed*/
{ -0.1472, -0.0341, 2.5605, -0.0755 }, /*high speed*/
{ -0.1379, -0.059, 2.5716, -0.0756 } /*Extreme Speed*/
};
/*****************************************************************************/
/* Function Declarations */
/*****************************************************************************/
picture_type_e ihevce_rc_conv_pic_type(
IV_PICTURE_CODING_TYPE_T pic_type,
WORD32 i4_field_pic,
WORD32 i4_temporal_layer_id,
WORD32 i4_is_bottom_field,
WORD32 i4_top_field_first);
WORD32 ihevce_rc_get_scaled_mpeg2_qp(WORD32 i4_frame_qp, rc_quant_t *ps_rc_quant_ctxt);
static WORD32 ihevce_get_offline_index(rc_context_t *ps_rc_ctxt, WORD32 i4_num_pels_in_frame);
static void ihevce_rc_get_pic_param(
picture_type_e rc_pic_type, WORD32 *pi4_tem_lyr, WORD32 *pi4_is_bottom_field);
static double ihevce_get_frame_lambda_modifier(
WORD8 slice_type,
WORD32 i4_rc_temporal_lyr_id,
WORD32 i4_first_field,
WORD32 i4_rc_is_ref_pic,
WORD32 i4_num_b_frms);
static WORD32 ihevce_clip_min_max_qp(
rc_context_t *ps_rc_ctxt,
WORD32 i4_hevc_frame_qp,
picture_type_e rc_pic_type,
WORD32 i4_rc_temporal_lyr_id);
WORD32 ihevce_ebf_based_rc_correction_to_avoid_overflow(
rc_context_t *ps_rc_ctxt, rc_lap_out_params_t *ps_rc_lap_out, WORD32 *pi4_tot_bits_estimated);
/*****************************************************************************/
/* Function Definitions */
/*****************************************************************************/
/*!
************************************************************************
* @brief
* return number of records used by RC
************************************************************************
*/
WORD32 ihevce_rc_get_num_mem_recs(void)
{
WORD32 i4_num_rc_mem_tab = 0;
/*get the number of memtab request from RC*/
rate_control_handle ps_rate_control_api;
itt_memtab_t *ps_memtab = NULL;
i4_num_rc_mem_tab =
rate_control_num_fill_use_free_memtab(&ps_rate_control_api, ps_memtab, GET_NUM_MEMTAB);
return ((NUM_RC_MEM_RECS + i4_num_rc_mem_tab));
}
/*!
************************************************************************
* @brief
* return each record attributes of RC
************************************************************************
*/
WORD32 ihevce_rc_get_mem_recs(
iv_mem_rec_t *ps_mem_tab,
ihevce_static_cfg_params_t *ps_init_prms,
WORD32 mem_space,
ihevce_sys_api_t *ps_sys_api)
{
float f_temp;
WORD32 i4_temp_size;
WORD32 i4_num_memtab = 0;
WORD32 i4_num_rc_mem_tab, i;
rate_control_handle ps_rate_control_api;
itt_memtab_t *ps_itt_memtab = NULL;
itt_memtab_t as_rc_mem_tab[30];
/*memory requirements to store RC context */
ps_mem_tab[RC_CTXT].i4_mem_size = sizeof(rc_context_t);
//DBG_PRINTF("size of RC context = %d\n",sizeof(rc_context_t));
ps_mem_tab[RC_CTXT].e_mem_type = (IV_MEM_TYPE_T)mem_space;
ps_mem_tab[RC_CTXT].i4_mem_alignment = 64;
(void)ps_sys_api;
//i4_temp_size = (51 + ((ps_init_prms->s_src_prms.i4_bit_depth - 8) * 6));
i4_temp_size = (51 + ((ps_init_prms->s_tgt_lyr_prms.i4_internal_bit_depth - 8) * 6));
ps_mem_tab[RC_QP_TO_QSCALE].i4_mem_size = (i4_temp_size + 1) * 4;
ps_mem_tab[RC_QP_TO_QSCALE].e_mem_type = (IV_MEM_TYPE_T)mem_space;
ps_mem_tab[RC_QP_TO_QSCALE].i4_mem_alignment = 64;
ps_mem_tab[RC_QP_TO_QSCALE_Q_FACTOR].i4_mem_size = (i4_temp_size + 1) * 4;
ps_mem_tab[RC_QP_TO_QSCALE_Q_FACTOR].e_mem_type = (IV_MEM_TYPE_T)mem_space;
ps_mem_tab[RC_QP_TO_QSCALE_Q_FACTOR].i4_mem_alignment = 64;
f_temp = (float)(51 + ((ps_init_prms->s_tgt_lyr_prms.i4_internal_bit_depth - 8) * 6));
f_temp = ((float)(f_temp - 4) / 6);
i4_temp_size = (WORD32)((float)pow(2, f_temp) + 0.5);
i4_temp_size = (i4_temp_size << 3); // Q3 format is mantained for accuarate calc at lower qp
ps_mem_tab[RC_QSCALE_TO_QP].i4_mem_size = (i4_temp_size + 1) * sizeof(UWORD32);
ps_mem_tab[RC_QSCALE_TO_QP].e_mem_type = (IV_MEM_TYPE_T)mem_space;
ps_mem_tab[RC_QSCALE_TO_QP].i4_mem_alignment = 64;
/*memory requirements to store RC context */
ps_mem_tab[RC_MULTI_PASS_GOP_STAT].i4_mem_size = sizeof(gop_level_stat_t);
ps_mem_tab[RC_MULTI_PASS_GOP_STAT].e_mem_type = (IV_MEM_TYPE_T)mem_space;
ps_mem_tab[RC_MULTI_PASS_GOP_STAT].i4_mem_alignment = 64;
i4_num_rc_mem_tab =
rate_control_num_fill_use_free_memtab(&ps_rate_control_api, ps_itt_memtab, GET_NUM_MEMTAB);
i4_num_memtab =
rate_control_num_fill_use_free_memtab(&ps_rate_control_api, as_rc_mem_tab, FILL_MEMTAB);
for(i = 0; i < i4_num_memtab; i++)
{
ps_mem_tab[i + NUM_RC_MEM_RECS].i4_mem_size = as_rc_mem_tab[i].u4_size;
ps_mem_tab[i + NUM_RC_MEM_RECS].i4_mem_alignment = as_rc_mem_tab[i].i4_alignment;
ps_mem_tab[i + NUM_RC_MEM_RECS].e_mem_type = (IV_MEM_TYPE_T)mem_space;
}
return (i4_num_memtab + NUM_RC_MEM_RECS);
}
/**
******************************************************************************
*
* @brief Initilizes the rate control module
*
* @par Description
*
* @param[inout] ps_mem_tab
* pointer to memory descriptors table
*
* @param[in] ps_init_prms
* Create time static parameters
*
* @return void
*
******************************************************************************
*/
void *ihevce_rc_mem_init(
iv_mem_rec_t *ps_mem_tab,
ihevce_static_cfg_params_t *ps_init_prms,
WORD32 i4_bitrate_instance_id,
rc_quant_t *ps_rc_quant,
WORD32 i4_resolution_id,
WORD32 i4_look_ahead_frames_in_first_pass)
{
rc_context_t *ps_rc_ctxt;
WORD32 i4_num_memtab, i, j, i4_avg_bitrate, u4_buf_size;
WORD32 i4_cdr_period = 0, i4_idr_period = 0;
WORD32 i4_peak_bitrate_factor;
rate_control_handle ps_rate_control_api;
itt_memtab_t as_rc_mem_tab[30];
itt_memtab_t *ps_itt_memtab = NULL;
ps_rc_ctxt = (rc_context_t *)ps_mem_tab[RC_CTXT].pv_base;
memset(ps_rc_ctxt, 0, sizeof(rc_context_t));
ps_rc_ctxt->i4_br_id_for_2pass = i4_bitrate_instance_id;
if(ps_init_prms->s_coding_tools_prms.i4_max_cra_open_gop_period)
{
i4_cdr_period = ps_init_prms->s_coding_tools_prms.i4_max_cra_open_gop_period;
}
if(ps_init_prms->s_coding_tools_prms.i4_max_i_open_gop_period)
{
i4_cdr_period = ps_init_prms->s_coding_tools_prms.i4_max_i_open_gop_period;
}
i4_idr_period = ps_init_prms->s_coding_tools_prms.i4_max_closed_gop_period;
ps_rc_quant->pi4_qscale_to_qp = (WORD32 *)ps_mem_tab[RC_QSCALE_TO_QP].pv_base;
ps_rc_quant->pi4_qp_to_qscale_q_factor = (WORD32 *)ps_mem_tab[RC_QP_TO_QSCALE_Q_FACTOR].pv_base;
ps_rc_quant->pi4_qp_to_qscale = (WORD32 *)ps_mem_tab[RC_QP_TO_QSCALE].pv_base;
ps_rc_ctxt->pv_gop_stat = (void *)ps_mem_tab[RC_MULTI_PASS_GOP_STAT].pv_base;
/*assign memtabs to rc module*/
i4_num_memtab =
rate_control_num_fill_use_free_memtab(&ps_rate_control_api, ps_itt_memtab, GET_NUM_MEMTAB);
i4_num_memtab =
rate_control_num_fill_use_free_memtab(&ps_rate_control_api, as_rc_mem_tab, FILL_MEMTAB);
for(i = 0; i < i4_num_memtab; i++)
{
as_rc_mem_tab[i].pv_base = ps_mem_tab[i + NUM_RC_MEM_RECS].pv_base;
}
i4_num_memtab =
rate_control_num_fill_use_free_memtab(&ps_rate_control_api, as_rc_mem_tab, USE_BASE);
ps_rc_ctxt->rc_hdl =
ps_rate_control_api; /*handle to entire RC structure private to RC library*/
ps_rc_ctxt->i4_field_pic = ps_init_prms->s_src_prms.i4_field_pic;
ps_rc_ctxt->i4_is_first_frame_encoded = 0;
/*added for field encoding*/
ps_rc_ctxt->i4_max_inter_frm_int =
1 << (ps_init_prms->s_coding_tools_prms.i4_max_temporal_layers + ps_rc_ctxt->i4_field_pic);
ps_rc_ctxt->i4_max_temporal_lyr = ps_init_prms->s_coding_tools_prms.i4_max_temporal_layers;
/*Number of picture types used if different models are used for hierarchial B frames*/
if(i4_idr_period == 1 || i4_cdr_period == 1)
ps_rc_ctxt->i4_num_active_pic_type = 1;
else
ps_rc_ctxt->i4_num_active_pic_type =
2 + ps_init_prms->s_coding_tools_prms.i4_max_temporal_layers;
ps_rc_ctxt->i4_quality_preset =
ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_quality_preset;
if(ps_rc_ctxt->i4_quality_preset == IHEVCE_QUALITY_P7)
{
ps_rc_ctxt->i4_quality_preset = IHEVCE_QUALITY_P6;
}
ps_rc_ctxt->i4_rc_pass = ps_init_prms->s_pass_prms.i4_pass;
ps_rc_ctxt->i8_num_gop_mem_alloc = 0;
ps_rc_ctxt->u1_is_mb_level_rc_on = 0; /*no mb level RC*/
ps_rc_ctxt->i4_is_infinite_gop = 0;
ps_rc_ctxt->u1_bit_depth = (UWORD8)ps_init_prms->s_tgt_lyr_prms.i4_internal_bit_depth;
//ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset = ((ps_init_prms->s_src_prms.i4_bit_depth-8)*6);
ps_rc_quant->i1_qp_offset = ((ps_init_prms->s_tgt_lyr_prms.i4_internal_bit_depth - 8) * 6);
ps_rc_quant->i2_max_qp = MIN(ps_init_prms->s_config_prms.i4_max_frame_qp,
51); // FOR Encoder
ps_rc_quant->i2_min_qp =
MAX(-(ps_rc_quant->i1_qp_offset), ps_init_prms->s_config_prms.i4_min_frame_qp);
if(ps_init_prms->s_lap_prms.i4_rc_look_ahead_pics)
{
ps_rc_ctxt->i4_num_frame_in_lap_window =
ps_init_prms->s_lap_prms.i4_rc_look_ahead_pics + MIN_L1_L0_STAGGER_NON_SEQ;
}
else
ps_rc_ctxt->i4_num_frame_in_lap_window = 0;
if(i4_cdr_period > 0 && i4_idr_period > 0)
{
/*both IDR and CDR are positive*/
//WORD32 i4_rem;
ps_rc_ctxt->u4_intra_frame_interval = i4_cdr_period;
ps_rc_ctxt->u4_idr_period = i4_idr_period;
/*Allow configuration where IDR period is multiple of CDR period. Though any configuiration is supported by LAP rate control
does not handle assymeteric GOPS, Bit-allocation is exposed to CDR or IDR. It treats everything as I pic*/
}
else if(!i4_idr_period && i4_cdr_period > 0)
{
ps_rc_ctxt->u4_intra_frame_interval = i4_cdr_period;
ps_rc_ctxt->u4_idr_period = 0;
}
else if(!i4_cdr_period && i4_idr_period > 0)
{
ps_rc_ctxt->u4_intra_frame_interval = i4_idr_period;
ps_rc_ctxt->u4_idr_period = i4_idr_period;
}
else
{
/*ASSERT(0);*/
ps_rc_ctxt->u4_intra_frame_interval =
INFINITE_GOP_CDR_TIME_S *
((ps_init_prms->s_src_prms.i4_frm_rate_num /
(ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_frm_rate_scale_factor *
ps_init_prms->s_src_prms.i4_frm_rate_denom)));
ps_rc_ctxt->u4_idr_period = 0;
ps_rc_ctxt->i4_is_infinite_gop = 1;
}
/*If cdr period is 0 then only it is closed gop*/
ps_rc_ctxt->i4_is_gop_closed = 0;
if(i4_cdr_period == 0)
{
ps_rc_ctxt->i4_is_gop_closed = 1;
}
/*This is required because the intra sad returned by non I pic is not correct. Use only I pic sad for next I pic qp calculation*/
ps_rc_ctxt->i4_use_est_intra_sad = 0;
ps_rc_ctxt->u4_src_ticks = 1000;
ps_rc_ctxt->u4_tgt_ticks = 1000;
ps_rc_ctxt->i4_auto_generate_init_qp = 1;
ps_rc_ctxt->i8_prev_i_frm_cost = 0;
for(i = 0; i < MAX_PIC_TYPE; i++)
{
/* -1 cost indicates the picture type not been encoded*/
ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[i] = -1;
ps_rc_ctxt->ai8_prev_frame_est_L0_satd[i] = -1;
ps_rc_ctxt->ai8_prev_frame_hme_sad[i] = -1;
ps_rc_ctxt->ai8_prev_frame_pre_intra_sad[i] = -1;
/*L1 state metrics*/
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_I_intra_raw_satd[i] = -1;
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_cost[i] = -1;
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_sad[i] = -1;
/* SGI & Enc Loop Parallelism related changes*/
ps_rc_ctxt->s_l1_state_metric.au4_prev_scene_num[i] = 0;
ps_rc_ctxt->au4_prev_scene_num_pre_enc[i] = 0xFFFFFFFF;
ps_rc_ctxt->ai4_qp_for_previous_scene_pre_enc[i] = 0;
}
ps_rc_ctxt->u4_scene_num_est_L0_intra_sad_available = 0xFFFFFFFF;
for(i = 0; i < MAX_NON_REF_B_PICS_IN_QUEUE_SGI; i++)
{
ps_rc_ctxt->as_non_ref_b_qp[i].i4_enc_order_num_rc = 0x7FFFFFFF;
ps_rc_ctxt->as_non_ref_b_qp[i].i4_non_ref_B_pic_qp = 0x7FFFFFFF;
ps_rc_ctxt->as_non_ref_b_qp[i].u4_scene_num_rc = MAX_SCENE_NUM + 1;
}
ps_rc_ctxt->i4_non_ref_B_ctr = 0;
ps_rc_ctxt->i4_prev_qp_ctr = 0;
ps_rc_ctxt->i4_cur_scene_num = 0;
/*init = 0 set to 1 when atleast one frame of each picture type has completed L1 stage*/
ps_rc_ctxt->i4_is_est_L0_intra_sad_available = 0;
/*Min and max qp from user*/
ps_rc_ctxt->i4_min_frame_qp = ps_init_prms->s_config_prms.i4_min_frame_qp;
ps_rc_ctxt->i4_max_frame_qp = ps_init_prms->s_config_prms.i4_max_frame_qp;
ASSERT(ps_rc_ctxt->i4_min_frame_qp >= ps_rc_quant->i2_min_qp);
ASSERT(ps_rc_ctxt->i4_max_frame_qp <= ps_rc_quant->i2_max_qp);
/*bitrate init*/
/*take average bitrate from comfig file*/
i4_avg_bitrate = ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id]
.ai4_tgt_bitrate[i4_bitrate_instance_id];
if((ps_init_prms->s_config_prms.i4_rate_control_mode == VBR_STREAMING) &&
(ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id]
.ai4_peak_bitrate[i4_bitrate_instance_id] < (1050 * (i4_avg_bitrate / 1000))))
{
ps_init_prms->s_config_prms.i4_rate_control_mode = CBR_NLDRC;
}
ps_rc_ctxt->e_rate_control_type = (rc_type_e)ps_init_prms->s_config_prms.i4_rate_control_mode;
ps_rc_ctxt->i4_capped_vbr_flag = 0;
if(1 == ps_init_prms->s_config_prms.i4_rate_control_mode)
{
/* The path taken by capped vbr mode is same as normal VBR mode. Only a flag needs to be enabled
which tells the rc module that encoder is running in capped vbr mode */
ps_rc_ctxt->e_rate_control_type = VBR_STREAMING;
ps_rc_ctxt->i4_capped_vbr_flag = 1;
}
ASSERT(
(ps_rc_ctxt->e_rate_control_type == CBR_NLDRC) ||
(ps_rc_ctxt->e_rate_control_type == CONST_QP) ||
(ps_rc_ctxt->e_rate_control_type == VBR_STREAMING));
ps_rc_ctxt->u4_avg_bit_rate = i4_avg_bitrate;
for(i = 0; i < MAX_PIC_TYPE; i++)
{
if(ps_rc_ctxt->e_rate_control_type == VBR_STREAMING)
{
ps_rc_ctxt->au4_peak_bit_rate[i] =
ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id]
.ai4_peak_bitrate[i4_bitrate_instance_id];
}
else
{
/*peak bitrate parameter is ignored in CBR*/
ps_rc_ctxt->au4_peak_bit_rate[i] = i4_avg_bitrate;
}
}
ps_rc_ctxt->u4_min_bit_rate = i4_avg_bitrate;
/*buffer size init*/
u4_buf_size = (WORD32)(ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id]
.ai4_max_vbv_buffer_size[i4_bitrate_instance_id]);
ps_rc_ctxt->u4_max_delay = (UWORD32)(
(float)u4_buf_size / i4_avg_bitrate * 1000); /*delay in milli-seconds based on buffer size*/
ps_rc_ctxt->u4_max_vbv_buff_size = u4_buf_size; /*buffer size should be in bits*/
/*This dictates the max deviaiton allowed for file size in VBR mode. */
ps_rc_ctxt->f_vbr_max_peak_sustain_dur =
((float)ps_init_prms->s_config_prms.i4_vbr_max_peak_rate_dur) / 1000;
ps_rc_ctxt->i8_num_frms_to_encode = (WORD32)ps_init_prms->s_config_prms.i4_num_frms_to_encode;
i4_peak_bitrate_factor = (ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id]
.ai4_peak_bitrate[i4_bitrate_instance_id] /
i4_avg_bitrate) *
1000;
{
//float f_delay = ((float)ps_init_prms->s_config_prms.i4_max_vbv_buffer_size*1000)/i4_peak_bitrate_factor;
float f_delay = ((float)ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id]
.ai4_max_vbv_buffer_size[i4_bitrate_instance_id] *
1000) /
ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id]
.ai4_peak_bitrate[i4_bitrate_instance_id];
ps_rc_ctxt->i4_initial_decoder_delay_frames = (WORD32)(
((f_delay) * (ps_init_prms->s_src_prms.i4_frm_rate_num /
(ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id]
.i4_frm_rate_scale_factor *
ps_init_prms->s_src_prms.i4_frm_rate_denom))) /
1000);
}
/*Initial buffer fullness*/
ps_rc_ctxt->i4_init_vbv_fullness = ps_init_prms->s_config_prms.i4_init_vbv_fullness;
/*Init Qp updation. This seems to be used for pre enc stage of second frame. Needs to be looked into*/
ps_rc_ctxt->i4_init_frame_qp_user = ps_init_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id]
.ai4_frame_qp[i4_bitrate_instance_id];
for(i = 0; i < MAX_SCENE_NUM; i++)
{
for(j = 0; j < MAX_PIC_TYPE; j++)
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i][j] = INIT_HEVCE_QP_RC;
}
memset(&ps_rc_ctxt->ai4_scene_numbers[0], 0, sizeof(ps_rc_ctxt->ai4_scene_numbers));
memset(&ps_rc_ctxt->ai4_scene_num_last_pic[0], 0, sizeof(ps_rc_ctxt->ai4_scene_num_last_pic));
ps_rc_ctxt->ai4_last_tw0_lyr0_pic_qp[0] = ps_rc_ctxt->i4_min_frame_qp - 1;
ps_rc_ctxt->ai4_last_tw0_lyr0_pic_qp[1] = ps_rc_ctxt->i4_min_frame_qp - 1;
/* SGI & Enc Loop Parallelism related changes*/
for(i = 0; i < MAX_NUM_ENC_LOOP_PARALLEL; i++)
{
ps_rc_ctxt->ai8_cur_frm_intra_cost[i] = 0;
ps_rc_ctxt->ai8_cur_frame_coarse_ME_cost[i] = 0;
ps_rc_ctxt->ai4_I_model_only_reset[i] = 0;
ps_rc_ctxt->ai4_is_non_I_scd_pic[i] = 0;
ps_rc_ctxt->ai4_is_pause_to_resume[i] = 0;
ps_rc_ctxt->ai4_is_cmplx_change_reset_model[i] = 0;
ps_rc_ctxt->ai4_is_cmplx_change_reset_bits[i] = 0;
/*initialize assuming 30 percent intra and 70 percent inter weightage*/
ps_rc_ctxt->ai4_lap_complexity_q7[i] = MODERATE_LAP2_COMPLEXITY_Q7;
ps_rc_ctxt->ai4_lap_f_sim[i] = MODERATE_FSIM_VALUE;
}
/*Init variables required to handle entropy and rdopt consumption mismatch*/
ps_rc_ctxt->i4_rdopt_bit_count = 0;
ps_rc_ctxt->i4_entropy_bit_count = 0;
for(i = 0; i < NUM_BUF_RDOPT_ENT_CORRECT; i++)
{
ps_rc_ctxt->ai4_rdopt_bit_consumption_estimate[i] =
-1; /*negative bit signifies that value is not populated*/
ps_rc_ctxt->ai4_rdopt_bit_consumption_buf_id[i] = -1;
ps_rc_ctxt->ai4_entropy_bit_consumption[i] = -1;
ps_rc_ctxt->ai4_entropy_bit_consumption_buf_id[i] = -1;
}
/** scd model reset related param init*/
for(i = 0; i < MAX_NUM_TEMPORAL_LAYERS; i++)
{
ps_rc_ctxt->au4_scene_num_temp_id[i] = 0;
}
/* SGI & Enc Loop Parallelism related changes*/
for(i = 0; i < MAX_NUM_ENC_LOOP_PARALLEL; i++)
{
ps_rc_ctxt->ai4_is_frame_scd[i] = 0;
}
/*Stat file pointer passed from applicaition*/
ps_rc_ctxt->pf_stat_file = NULL;
ps_rc_ctxt->i8_num_frame_read = 0;
return ps_rc_ctxt;
}
/*###############################################*/
/******* END OF RC MEM INIT FUNCTIONS **********/
/*###############################################*/
/*###############################################*/
/******* START OF RC INIT FUNCTIONS **************/
/*###############################################*/
/**
******************************************************************************
*
* @brief Initialises teh Rate control ctxt
*
* @par Description
*
* @param[inout] pv_ctxt
* pointer to memory descriptors table
*
* @param[in] ps_run_time_src_param
* Create time static parameters
*
* @return void
*
******************************************************************************
*/
void ihevce_rc_init(
void *pv_ctxt,
ihevce_src_params_t *ps_run_time_src_param,
ihevce_tgt_params_t *ps_tgt_params,
rc_quant_t *ps_rc_quant,
ihevce_sys_api_t *ps_sys_api,
ihevce_lap_params_t *ps_lap_prms,
WORD32 i4_num_frame_parallel)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
WORD32 i, i_temp, j;
float f_temp;
/*run time width and height has to considered*/
ps_rc_ctxt->i4_frame_height = ps_tgt_params->i4_height;
ps_rc_ctxt->i4_frame_width = ps_tgt_params->i4_width;
ps_rc_ctxt->i4_field_pic = ps_run_time_src_param->i4_field_pic;
ps_rc_ctxt->i8_num_bit_alloc_period = 0;
ps_rc_ctxt->i8_new_bitrate = -1; /*-1 indicates no dynamic change in bitrate request pending*/
ps_rc_ctxt->i8_new_peak_bitrate = -1;
ps_rc_ctxt->i4_is_last_frame_scan = 0;
memset(ps_rc_ctxt->ai4_offsets, 0, 5 * sizeof(WORD32));
ps_rc_ctxt->i4_complexity_bin = 5;
ps_rc_ctxt->i4_last_p_or_i_frame_gop = 0;
ps_rc_ctxt->i4_qp_at_I_frame_for_skip_sad = 1;
ps_rc_ctxt->i4_denominator_i_to_avg = 1;
ps_rc_ctxt->i4_fp_bit_alloc_in_sp = 0;
ps_rc_ctxt->ai4_offsets[0] = 0;
ps_rc_ctxt->ai4_offsets[1] = 1;
ps_rc_ctxt->ai4_offsets[2] = 2;
ps_rc_ctxt->ai4_offsets[3] = 3;
ps_rc_ctxt->ai4_offsets[4] = 4;
ps_rc_ctxt->i4_num_frames_subgop = 0;
ps_rc_ctxt->i8_total_acc_coarse_me_sad = 0;
ps_rc_ctxt->i4_L0_frame_qp = 1;
ps_rc_ctxt->i4_est_text_bits_ctr_get_qp = 0;
ps_rc_ctxt->i4_est_text_bits_ctr_update_qp = 0;
/*CAllback functions need to be copied for use inside RC*/
ps_rc_ctxt->ps_sys_rc_api = ps_sys_api;
f_temp = ((float)(ps_rc_quant->i2_max_qp + ps_rc_quant->i1_qp_offset - 4) / 6);
ps_rc_quant->i2_max_qscale = (WORD16)((float)pow(2, f_temp) + 0.5) << 3;
f_temp = ((float)(ps_rc_quant->i2_min_qp + ps_rc_quant->i1_qp_offset - 4) / 6);
ps_rc_quant->i2_min_qscale = (WORD16)((float)pow(2, f_temp) + 0.5);
f_temp =
((float)(51 + ps_rc_quant->i1_qp_offset - 4) /
6); // default MPEG2 to HEVC and HEVC to MPEG2 Qp conversion tables
i_temp = (WORD16)((float)pow(2, f_temp) + 0.5);
i_temp = (i_temp << 3); // Q3 format is mantained for accuarate calc at lower qp
for(i = 0; i <= i_temp; i++)
{
ps_rc_quant->pi4_qscale_to_qp[i] =
ihevce_rc_get_scaled_hevce_qp_q3(i, ps_rc_ctxt->u1_bit_depth);
}
for(i = (0 - ps_rc_quant->i1_qp_offset); i <= 51; i++)
{
ps_rc_quant->pi4_qp_to_qscale_q_factor[i + ps_rc_quant->i1_qp_offset] =
ihevce_rc_get_scaled_mpeg2_qp_q6(
i + ps_rc_quant->i1_qp_offset, ps_rc_ctxt->u1_bit_depth);
ps_rc_quant->pi4_qp_to_qscale[i + ps_rc_quant->i1_qp_offset] =
((ps_rc_quant->pi4_qp_to_qscale_q_factor[i + ps_rc_quant->i1_qp_offset] +
(1 << (QSCALE_Q_FAC_3 - 1))) >>
QSCALE_Q_FAC_3);
}
if(ps_rc_quant->i2_min_qscale < 1)
{
ps_rc_quant->i2_min_qscale = 1;
}
ps_rc_ctxt->ps_rc_quant_ctxt = ps_rc_quant;
/*Frame rate init*/
ps_rc_ctxt->u4_max_frame_rate =
ps_run_time_src_param->i4_frm_rate_num / ps_tgt_params->i4_frm_rate_scale_factor;
ps_rc_ctxt->i4_top_field_first = ps_run_time_src_param->i4_topfield_first; /**/
/*min and max qp initialization*/
if(ps_rc_ctxt->i4_field_pic == 0)
{
WORD32 i4_max_qp = 0;
if(ps_rc_ctxt->u1_bit_depth == 10)
{
i4_max_qp = MAX_HEVC_QP_10bit;
}
else if(ps_rc_ctxt->u1_bit_depth == 12)
{
i4_max_qp = MAX_HEVC_QP_12bit;
}
else
{
i4_max_qp = MAX_HEVC_QP;
}
for(i = 0; i < MAX_PIC_TYPE; i++)
{
if((ps_rc_ctxt->i4_init_frame_qp_user + (2 * i) +
ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset) <=
i4_max_qp) //BUG_FIX related to init QP allocation
{
ps_rc_ctxt->ai4_init_qp[i] = (ps_rc_ctxt->ps_rc_quant_ctxt->pi4_qp_to_qscale
[(ps_rc_ctxt->i4_init_frame_qp_user + (2 * i)) +
ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset] +
(1 << (QSCALE_Q_FAC_3 - 1))) >>
QSCALE_Q_FAC_3;
}
else
{
ps_rc_ctxt->ai4_init_qp[i] =
(ps_rc_ctxt->ps_rc_quant_ctxt->pi4_qp_to_qscale[i4_max_qp] +
(1 << (QSCALE_Q_FAC_3 - 1))) >>
QSCALE_Q_FAC_3; // + ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset];
}
ps_rc_ctxt->ai4_min_max_qp[i * 2] =
ps_rc_ctxt->ps_rc_quant_ctxt->i2_min_qscale; /*min qp for each picture type*/
ps_rc_ctxt->ai4_min_max_qp[i * 2 + 1] = ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qscale >>
QSCALE_Q_FAC_3; /*max qp for each picture type*/
}
}
else
{
WORD32 i4_num_pic_types = MAX_PIC_TYPE;
WORD32 i4_max_qp = 0;
if(ps_rc_ctxt->u1_bit_depth == 10)
{
i4_max_qp = MAX_HEVC_QP_10bit;
}
else if(ps_rc_ctxt->u1_bit_depth == 12)
{
i4_max_qp = MAX_HEVC_QP_12bit;
}
else
{
i4_max_qp = MAX_HEVC_QP;
}
i4_num_pic_types >>= 1;
for(i = 0; i < i4_num_pic_types; i++)
{
if((ps_rc_ctxt->i4_init_frame_qp_user + (2 * i) +
ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset) <= i4_max_qp)
{
ps_rc_ctxt->ai4_init_qp[i] = (ps_rc_ctxt->ps_rc_quant_ctxt->pi4_qp_to_qscale
[(ps_rc_ctxt->i4_init_frame_qp_user + (2 * i)) +
ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset] +
(1 << (QSCALE_Q_FAC_3 - 1))) >>
QSCALE_Q_FAC_3;
if(i != 0)
ps_rc_ctxt->ai4_init_qp[i + FIELD_OFFSET] = ps_rc_ctxt->ai4_init_qp[i];
}
else
{
ps_rc_ctxt->ai4_init_qp[i] =
(ps_rc_ctxt->ps_rc_quant_ctxt->pi4_qp_to_qscale[i4_max_qp] +
(1 << (QSCALE_Q_FAC_3 - 1))) >>
QSCALE_Q_FAC_3; // + ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset];
if(i != 0)
ps_rc_ctxt->ai4_init_qp[i + FIELD_OFFSET] = ps_rc_ctxt->ai4_init_qp[i];
}
ps_rc_ctxt->ai4_min_max_qp[i * 2] =
ps_rc_ctxt->ps_rc_quant_ctxt->i2_min_qscale; /*min qp for each picture type*/
ps_rc_ctxt->ai4_min_max_qp[i * 2 + 1] = ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qscale >>
QSCALE_Q_FAC_3; /*max qp for each picture type*/
if(i != 0)
{
ps_rc_ctxt->ai4_min_max_qp[(i + FIELD_OFFSET) * 2] =
ps_rc_ctxt->ps_rc_quant_ctxt->i2_min_qscale; /*min qp for each picture type*/
ps_rc_ctxt->ai4_min_max_qp[(i + FIELD_OFFSET) * 2 + 1] =
ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qscale; /*max qp for each picture type*/
}
}
}
for(j = 0; i < MAX_NUM_ENC_LOOP_PARALLEL; i++)
{
/*initialise the coeffs to 1 in case lap is not used */
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->af_sum_weigh[j][i][0] = 1.0;
ps_rc_ctxt->af_sum_weigh[j][i][1] = 0.0;
ps_rc_ctxt->af_sum_weigh[j][i][2] = 0.0;
}
}
ps_rc_ctxt->i4_num_frame_parallel = i4_num_frame_parallel; //ELP_RC
i4_num_frame_parallel = (i4_num_frame_parallel > 1) ? i4_num_frame_parallel : 0;
if(ps_rc_ctxt->i4_num_frame_parallel > 1)
{
ps_rc_ctxt->i4_pre_enc_rc_delay = MAX_PRE_ENC_RC_DELAY;
}
else
{
ps_rc_ctxt->i4_pre_enc_rc_delay = MIN_PRE_ENC_RC_DELAY;
}
/*Bitrate and resolutioon based scene cut min qp*/
{
/*The min qp for scene cut frame is chosen based on bitrate*/
float i4_bpp = ((float)ps_rc_ctxt->u4_avg_bit_rate / ps_rc_ctxt->u4_max_frame_rate) * 1000 /
(ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width);
if(ps_rc_ctxt->u4_intra_frame_interval == 1)
{
/*Ultra High resolution)*/
if((ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width) > 5000000)
{
if(i4_bpp > 0.24)
{
ps_rc_ctxt->i4_min_scd_hevc_qp = SCD_MIN_HEVC_QP_VHBR;
}
else if(i4_bpp > 0.16)
ps_rc_ctxt->i4_min_scd_hevc_qp =
SCD_MIN_HEVC_QP_HBR; /*corresponds to bitrate greater than 40mbps for 4k 30p*/
else
ps_rc_ctxt->i4_min_scd_hevc_qp = SCD_MIN_HEVC_QP;
}
else
{
if(i4_bpp > 0.32)
{
ps_rc_ctxt->i4_min_scd_hevc_qp = SCD_MIN_HEVC_QP_VHBR;
}
else if(i4_bpp > 0.24)
ps_rc_ctxt->i4_min_scd_hevc_qp =
SCD_MIN_HEVC_QP_HBR; /*corresponds to bitrate greater than 15mbps for 1080 30p*/
else
ps_rc_ctxt->i4_min_scd_hevc_qp = SCD_MIN_HEVC_QP;
}
}
else
{
/*Ultra High resolution)*/
if((ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width) > 5000000)
{
if(i4_bpp > 0.16)
{
ps_rc_ctxt->i4_min_scd_hevc_qp = SCD_MIN_HEVC_QP_VHBR;
}
else if(i4_bpp > 0.08)
ps_rc_ctxt->i4_min_scd_hevc_qp =
SCD_MIN_HEVC_QP_HBR; /*corresponds to bitrate greater than 20mbps for 4k 30p*/
else
ps_rc_ctxt->i4_min_scd_hevc_qp = SCD_MIN_HEVC_QP;
}
else
{
/*Resolution lesser than full HD (including )*/
if(i4_bpp > 0.24)
{
ps_rc_ctxt->i4_min_scd_hevc_qp = SCD_MIN_HEVC_QP_VHBR;
}
else if(i4_bpp > 0.16)
ps_rc_ctxt->i4_min_scd_hevc_qp =
SCD_MIN_HEVC_QP_HBR; /*corresponds to bitrate greater than 10mbps for 1080 30p*/
else
ps_rc_ctxt->i4_min_scd_hevc_qp = SCD_MIN_HEVC_QP;
}
}
}
initialise_rate_control(
ps_rc_ctxt->rc_hdl,
ps_rc_ctxt->e_rate_control_type,
ps_rc_ctxt->u1_is_mb_level_rc_on, //0,/*disabling MB level RC*/
ps_rc_ctxt->u4_avg_bit_rate,
ps_rc_ctxt->au4_peak_bit_rate,
ps_rc_ctxt->u4_min_bit_rate,
ps_rc_ctxt->u4_max_frame_rate,
ps_rc_ctxt->u4_max_delay, /*max delay in milli seconds based on buffer size*/
ps_rc_ctxt->u4_intra_frame_interval,
ps_rc_ctxt->u4_idr_period,
ps_rc_ctxt->ai4_init_qp,
ps_rc_ctxt->u4_max_vbv_buff_size,
ps_rc_ctxt->i4_max_inter_frm_int,
ps_rc_ctxt->i4_is_gop_closed,
ps_rc_ctxt->ai4_min_max_qp, /*min and max qp to be used for each of picture type*/
ps_rc_ctxt->i4_use_est_intra_sad,
ps_rc_ctxt->u4_src_ticks,
ps_rc_ctxt->u4_tgt_ticks,
ps_rc_ctxt->i4_frame_height, /*pels in frame considering 420 semi planar format*/
ps_rc_ctxt->i4_frame_width,
ps_rc_ctxt->i4_num_active_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_ctxt->i4_quality_preset,
ps_rc_ctxt->i4_num_frame_in_lap_window,
ps_rc_ctxt->i4_initial_decoder_delay_frames,
ps_rc_ctxt->f_vbr_max_peak_sustain_dur,
ps_rc_ctxt->i8_num_frms_to_encode,
ps_rc_ctxt->i4_min_scd_hevc_qp,
ps_rc_ctxt->u1_bit_depth,
ps_rc_ctxt->pf_stat_file,
ps_rc_ctxt->i4_rc_pass,
ps_rc_ctxt->pv_gop_stat,
ps_rc_ctxt->i8_num_gop_mem_alloc,
ps_rc_ctxt->i4_is_infinite_gop,
sizeof(ihevce_lap_output_params_t),
sizeof(rc_lap_out_params_t),
(void *)ps_sys_api,
ps_rc_ctxt->i4_fp_bit_alloc_in_sp,
i4_num_frame_parallel,
ps_rc_ctxt->i4_capped_vbr_flag);
//ps_rc_ctxt->i4_init_vbv_fullness = 500000;
rc_init_set_ebf(ps_rc_ctxt->rc_hdl, ps_rc_ctxt->i4_init_vbv_fullness);
/*get init qp based on ebf for rate control*/
if(ps_rc_ctxt->e_rate_control_type != CONST_QP)
{
WORD32 I_frame_qp, I_frame_mpeg2_qp;
/*assume moderate fsim*/
WORD32 i4_fsim_global = MODERATE_FSIM_VALUE;
I_frame_mpeg2_qp = rc_get_bpp_based_scene_cut_qp(
ps_rc_ctxt->rc_hdl,
I_PIC,
((3 * ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width) >> 1),
i4_fsim_global,
ps_rc_ctxt->af_sum_weigh[0],
1);
I_frame_qp = ihevce_rc_get_scaled_hevc_qp_from_qs_q3(
I_frame_mpeg2_qp << QSCALE_Q_FAC_3, ps_rc_ctxt->ps_rc_quant_ctxt);
I_frame_qp = I_frame_qp + ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset;
if(I_frame_qp > 44)
I_frame_qp = 44;
ps_rc_ctxt->ai4_init_pre_enc_qp[I_PIC] = I_frame_qp;
ps_rc_ctxt->ai4_init_pre_enc_qp[P_PIC] = I_frame_qp + 1;
ps_rc_ctxt->ai4_init_pre_enc_qp[B_PIC] = I_frame_qp + 2;
ps_rc_ctxt->ai4_init_pre_enc_qp[B1_PIC] = I_frame_qp + 3;
ps_rc_ctxt->ai4_init_pre_enc_qp[B2_PIC] = I_frame_qp + 4;
/*Bottom fields*/
ps_rc_ctxt->ai4_init_pre_enc_qp[P1_PIC] = I_frame_qp + 1;
ps_rc_ctxt->ai4_init_pre_enc_qp[BB_PIC] = I_frame_qp + 2;
ps_rc_ctxt->ai4_init_pre_enc_qp[B11_PIC] = I_frame_qp + 3;
ps_rc_ctxt->ai4_init_pre_enc_qp[B22_PIC] = I_frame_qp + 4;
ps_rc_ctxt->i4_pre_enc_qp_read_index = 0;
ps_rc_ctxt->i4_pre_enc_qp_write_index = ps_rc_ctxt->i4_pre_enc_rc_delay - 1;
for(i = 0; i < ps_rc_ctxt->i4_pre_enc_rc_delay; i++)
{
/*initialize it to -1 to indicate it as not produced*/
ps_rc_ctxt->as_pre_enc_qp_queue[i].i4_is_qp_valid = -1;
}
for(i = 0; i < (ps_rc_ctxt->i4_pre_enc_qp_write_index); i++)
{
WORD32 j;
ps_rc_ctxt->as_pre_enc_qp_queue[i].i4_is_qp_valid = 1;
for(j = 0; j < MAX_PIC_TYPE; j++)
{
ps_rc_ctxt->as_pre_enc_qp_queue[i].ai4_quant[j] =
ps_rc_ctxt->ai4_init_pre_enc_qp[j];
ps_rc_ctxt->as_pre_enc_qp_queue[i].i4_scd_qp =
ps_rc_ctxt->ai4_init_pre_enc_qp[I_PIC];
}
}
ps_rc_ctxt->i4_use_qp_offset_pre_enc = 1;
ps_rc_ctxt->i4_num_frms_from_reset = 0;
/* SGI & Enc Loop Parallelism related changes*/
ps_rc_ctxt->u4_prev_scene_num = 0;
//ps_rc_ctxt->i4_use_init_qp_for_pre_enc = 0;
for(j = 0; j < MAX_NON_REF_B_PICS_IN_QUEUE_SGI; j++)
{
ps_rc_ctxt->au4_prev_scene_num_multi_scene[j] = 0x3FFFFFFF;
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->ai4_qp_for_previous_scene_multi_scene[j][i] =
ps_rc_ctxt->ai4_init_pre_enc_qp[i];
}
}
/* SGI & Enc Loop Parallelism related changes*/
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->ai4_qp_for_previous_scene[i] = ps_rc_ctxt->ai4_init_pre_enc_qp[i];
}
}
else
{
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->ai4_init_pre_enc_qp[i] = ps_rc_ctxt->i4_init_frame_qp_user;
ps_rc_ctxt->ai4_qp_for_previous_scene[i] = ps_rc_ctxt->i4_init_frame_qp_user;
}
}
}
/**
******************************************************************************
*
* @brief Populate common params from lap_out structure to rc_lap_out structure
* Also the init of some rc_lap_out params done here
* @par Description
*
* @param[in] ps_lap_out
* pointer to lap_out structure
*
* @param[out] ps_rc_lap_out
* pointer to rc_lap_out structure
*
* @return void
*
******************************************************************************
*/
void ihevce_rc_populate_common_params(
ihevce_lap_output_params_t *ps_lap_out, rc_lap_out_params_t *ps_rc_lap_out)
{
/* Update common params */
ps_rc_lap_out->i4_rc_pic_type = ps_lap_out->i4_pic_type;
ps_rc_lap_out->i4_rc_poc = ps_lap_out->i4_poc;
ps_rc_lap_out->i4_rc_temporal_lyr_id = ps_lap_out->i4_temporal_lyr_id;
ps_rc_lap_out->i4_rc_is_ref_pic = ps_lap_out->i4_is_ref_pic;
ps_rc_lap_out->i4_rc_scene_type = ps_lap_out->i4_scene_type;
ps_rc_lap_out->u4_rc_scene_num = ps_lap_out->u4_scene_num;
ps_rc_lap_out->i4_rc_display_num = ps_lap_out->i4_display_num;
ps_rc_lap_out->i4_rc_quality_preset = ps_lap_out->i4_quality_preset;
ps_rc_lap_out->i4_rc_first_field = ps_lap_out->i4_first_field;
/*params populated in LAP-2*/
ps_rc_lap_out->i8_frame_acc_coarse_me_cost = -1;
memset(ps_rc_lap_out->ai8_frame_acc_coarse_me_sad, -1, sizeof(WORD32) * 52);
ps_rc_lap_out->i8_pre_intra_satd = -1;
ps_rc_lap_out->i8_raw_pre_intra_sad = -1;
ps_rc_lap_out->i8_raw_l1_coarse_me_sad = -1;
ps_rc_lap_out->i4_is_rc_model_needs_to_be_updated = 1;
/* SGI & Enc Loop Parallelism related changes*/
ps_rc_lap_out->i4_ignore_for_rc_update = 0;
/*For 1 pass HQ I frames*/
ps_rc_lap_out->i4_complexity_bin = 5;
{
WORD32 ai4_offsets[5] = { 0, 1, 2, 3, 4 };
memmove(ps_rc_lap_out->ai4_offsets, ai4_offsets, sizeof(WORD32) * 5);
ps_rc_lap_out->i4_offsets_set_flag = -1;
}
ps_rc_lap_out->i4_L1_qp = -1;
ps_rc_lap_out->i4_L0_qp = -1;
}
/*###############################################*/
/******* END OF RC INIT FUNCTIONS **************/
/*###############################################*/
/*#########################################################*/
/******* START OF PRE-ENC QP QUERY FUNCTIONS **************/
/*#######################################################*/
/**
******************************************************************************
*
* @name ihevce_rc_get_bpp_based_frame_qp
*
* @par Description
*
* @param[in] ps_rc_ctxt - pointer to rc context
* ps_rc_lap_out
* @return frame qp
*
******************************************************************************
*/
WORD32 ihevce_rc_get_bpp_based_frame_qp(void *pv_rc_ctxt, rc_lap_out_params_t *ps_rc_lap_out)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
WORD32 i4_frame_qs_q3, i4_hevc_frame_qp, i;
frame_info_t *ps_frame_info;
picture_type_e rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_rc_lap_out->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
/*initialise the coeffs to 1 in case lap is not used */
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->af_sum_weigh[0][i][0] = 1.0;
ps_rc_ctxt->af_sum_weigh[0][i][1] = 0.0;
ps_rc_ctxt->af_sum_weigh[0][i][2] = 0.0;
}
{
/*scene cut handling during pre-enc stage*/
/*assume lap fsim as 117. not used since ratio is direclt sent*/
if(ps_rc_lap_out->i4_rc_scene_type == SCENE_TYPE_SCENE_CUT)
{
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->ai8_prev_frame_est_L0_satd[i] = -1;
ps_rc_ctxt->ai8_prev_frame_hme_sad[i] = -1;
ps_rc_ctxt->ai8_prev_frame_pre_intra_sad[i] = -1;
}
ps_rc_ctxt->i4_is_est_L0_intra_sad_available = 0;
}
if(ps_rc_lap_out->i4_rc_scene_type == SCENE_TYPE_SCENE_CUT ||
!ps_rc_ctxt->i4_is_est_L0_intra_sad_available)
{
/*compute bpp based qp if current frame is scene cut or data is not sufficient*/
i4_frame_qs_q3 = rc_get_bpp_based_scene_cut_qp(
ps_rc_ctxt->rc_hdl,
I_PIC,
((3 * ps_rc_lap_out->i4_num_pels_in_frame_considered) >> 1),
117,
ps_rc_ctxt->af_sum_weigh[0],
0);
i4_frame_qs_q3 = i4_frame_qs_q3 << QSCALE_Q_FAC_3;
}
else
{
/*using previous one sub-gop data calculate i to rest ratio and qp assuming it is I frame*/
WORD32 i4_num_b, i, ai4_pic_dist[MAX_PIC_TYPE], index, i4_total_bits;
LWORD64 i8_average_pre_intra_sad = 0, i8_average_est_l0_satd_by_act = 0;
double lambda_modifier[MAX_PIC_TYPE], complexity[MAX_PIC_TYPE], den = 0.0f,
i_to_rest_bit_ratio;
WORD32 i4_curr_bits_estimated = 0;
for(i = 0; i < MAX_PIC_TYPE; i++)
{
complexity[i] = 0;
lambda_modifier[i] = 0;
ai4_pic_dist[i] = 0;
}
index = ihevce_get_offline_index(
ps_rc_ctxt, ps_rc_lap_out->i4_num_pels_in_frame_considered);
if(ps_rc_ctxt->i4_max_temporal_lyr)
{
i4_num_b = ((WORD32)pow((float)2, ps_rc_ctxt->i4_max_temporal_lyr)) - 1;
}
else
{
i4_num_b = 0;
}
lambda_modifier[I_PIC] =
ihevce_get_frame_lambda_modifier((WORD8)I_PIC, 0, 1, 1, i4_num_b);
lambda_modifier[P_PIC] =
ihevce_get_frame_lambda_modifier((WORD8)P_PIC, 0, 1, 1, i4_num_b) *
pow((float)1.125, 1);
lambda_modifier[B_PIC] =
ihevce_get_frame_lambda_modifier(
(WORD8)B_PIC, 1, (ps_rc_ctxt->i4_max_temporal_lyr > 1), 1, i4_num_b) *
pow((float)1.125, 2);
lambda_modifier[B1_PIC] =
ihevce_get_frame_lambda_modifier(
(WORD8)B1_PIC, 2, 1, (ps_rc_ctxt->i4_max_temporal_lyr > 2), i4_num_b) *
pow((float)1.125, 3);
lambda_modifier[B2_PIC] =
ihevce_get_frame_lambda_modifier((WORD8)B2_PIC, 3, 1, 0, i4_num_b) *
pow((float)1.125, 4);
/*consider average of one sub-gop for intra sad*/
if(ps_rc_ctxt->i4_quality_preset == IHEVCE_QUALITY_P6)
{
for(i = 0; i < 2; i++)
{
i8_average_pre_intra_sad += ps_rc_ctxt->ai8_prev_frame_pre_intra_sad[i];
i8_average_est_l0_satd_by_act += ps_rc_ctxt->ai8_prev_frame_est_L0_satd[i];
if(ps_rc_ctxt->i4_field_pic == 1 && i != 0)
{
i8_average_pre_intra_sad +=
ps_rc_ctxt->ai8_prev_frame_pre_intra_sad[i + FIELD_OFFSET];
i8_average_est_l0_satd_by_act +=
ps_rc_ctxt->ai8_prev_frame_est_L0_satd[i + FIELD_OFFSET];
}
}
if(ps_rc_ctxt->i4_field_pic == 1)
{
i8_average_pre_intra_sad /= 3;
i8_average_est_l0_satd_by_act /= 3;
}
else
{
i8_average_pre_intra_sad <<= 1;
i8_average_est_l0_satd_by_act <<= 1;
}
}
else
{
for(i = 0; i < ps_rc_ctxt->i4_num_active_pic_type; i++)
{
i8_average_pre_intra_sad += ps_rc_ctxt->ai8_prev_frame_pre_intra_sad[i];
i8_average_est_l0_satd_by_act += ps_rc_ctxt->ai8_prev_frame_est_L0_satd[i];
if(ps_rc_ctxt->i4_field_pic == 1 && i != 0)
{
i8_average_pre_intra_sad +=
ps_rc_ctxt->ai8_prev_frame_pre_intra_sad[i + FIELD_OFFSET];
i8_average_est_l0_satd_by_act +=
ps_rc_ctxt->ai8_prev_frame_est_L0_satd[i + FIELD_OFFSET];
}
}
if(ps_rc_ctxt->i4_field_pic == 1)
{
i8_average_pre_intra_sad /= ((i << 1) - 1);
i8_average_est_l0_satd_by_act /= ((i << 1) - 1);
}
else
{
i8_average_pre_intra_sad /= i;
i8_average_est_l0_satd_by_act /= i;
}
}
/*no lambda modifier is considered for I pic as other lambda are scaled according to I frame lambda*/
complexity[I_PIC] = (double)i8_average_pre_intra_sad;
for(i = 1; i < ps_rc_ctxt->i4_num_active_pic_type; i++)
{
#if !USE_SQRT
complexity[i] = ps_rc_ctxt->ai8_prev_frame_hme_sad[i] / pow(1.125, i);
if(ps_rc_ctxt->i4_field_pic == 1)
{
complexity[i + FIELD_OFFSET] =
ps_rc_ctxt->ai8_prev_frame_hme_sad[i + FIELD_OFFSET] / pow(1.125, i);
}
#else
complexity[i] = ps_rc_ctxt->ai8_prev_frame_hme_sad[i] /
(sqrt(lambda_modifier[i] / lambda_modifier[I_PIC]) * pow(1.125, i));
#endif
}
/*get picture type distribution in LAP*/
rc_get_pic_distribution(ps_rc_ctxt->rc_hdl, &ai4_pic_dist[0]);
for(i = 0; i < MAX_PIC_TYPE; i++)
{
den += complexity[i] * ai4_pic_dist[i];
}
/*subtract I frame complexity to get I to rest ratio*/
{
WORD32 num_inter_pic = 0;
for(i = 1; i < MAX_PIC_TYPE; i++)
{
num_inter_pic += ai4_pic_dist[i];
}
if(num_inter_pic > 0)
den = (den - (complexity[I_PIC] * ai4_pic_dist[I_PIC])) / num_inter_pic;
else
den = complexity[I_PIC];
}
if(den > 0)
i_to_rest_bit_ratio = (float)((complexity[I_PIC]) / den);
else
i_to_rest_bit_ratio = 15;
/*get qp for scene cut frame based on offline data*/
i4_frame_qs_q3 = rc_get_qp_for_scd_frame(
ps_rc_ctxt->rc_hdl,
I_PIC,
i8_average_est_l0_satd_by_act,
ps_rc_lap_out->i4_num_pels_in_frame_considered,
-1,
MODERATE_FSIM_VALUE,
(void *)&g_offline_i_model_coeff[index][0],
(float)i_to_rest_bit_ratio,
0,
ps_rc_ctxt->af_sum_weigh[0],
ps_rc_lap_out->ps_frame_info,
ps_rc_ctxt->i4_rc_pass,
0,
0,
0,
&i4_total_bits,
&i4_curr_bits_estimated,
ps_rc_lap_out->i4_use_offline_model_2pass,
0,
0,
-1,
NULL);
}
i4_hevc_frame_qp =
ihevce_rc_get_scaled_hevc_qp_from_qs_q3(i4_frame_qs_q3, ps_rc_ctxt->ps_rc_quant_ctxt);
i4_hevc_frame_qp = i4_hevc_frame_qp + ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset;
if(i4_hevc_frame_qp > ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qp)
i4_hevc_frame_qp = ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qp;
/*offset depending on current picture type*/
if(rc_pic_type != I_PIC)
i4_hevc_frame_qp += ps_rc_lap_out->i4_rc_temporal_lyr_id + 1;
/*clip min and max qp to be within range*/
i4_hevc_frame_qp = ihevce_clip_min_max_qp(
ps_rc_ctxt, i4_hevc_frame_qp, rc_pic_type, ps_rc_lap_out->i4_rc_temporal_lyr_id);
ps_rc_ctxt->ai4_qp_for_previous_scene_pre_enc[rc_pic_type] = i4_hevc_frame_qp;
ps_rc_ctxt->au4_prev_scene_num_pre_enc[rc_pic_type] = ps_rc_lap_out->u4_rc_scene_num;
}
return i4_hevc_frame_qp;
}
/**
******************************************************************************
*
* @name ihevce_rc_get_pre_enc_pic_quant
*
* @par Description - Called from ihevce_rc_cal_pre_enc_qp. updates frame qp
* which will be used by next frame of same pic type in
* pre-enc stage
*
* @param[in] ps_rc_ctxt - pointer to rc context
* @return void
*
******************************************************************************
*/
WORD32
ihevce_rc_get_pre_enc_pic_quant(void *pv_ctxt, picture_type_e rc_pic_type, WORD32 *pi4_scd_qp)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
WORD32 i4_frame_qp, i4_frame_qp_q6, i4_hevc_frame_qp = -1;
WORD32 i4_max_frame_bits = (1 << 30);
WORD32 i4_temporal_layer_id, i4_is_bottom_field, i4_cur_est_texture_bits;
ihevce_rc_get_pic_param(rc_pic_type, &i4_temporal_layer_id, &i4_is_bottom_field);
{
WORD32 is_scd_ref_frame = 0, i4_num_scd_in_lap_window = 0, num_frames_b4_scd = 0;
/*treat even first frame as scd frame*/
if(!ps_rc_ctxt->i4_is_first_frame_encoded)
{
is_scd_ref_frame = 1;
}
{
/*Only I frames are considered as scd pic during pre-enc*/
is_scd_ref_frame &= (rc_pic_type == I_PIC);
}
rc_set_num_scd_in_lap_window(
ps_rc_ctxt->rc_hdl, i4_num_scd_in_lap_window, num_frames_b4_scd);
/** Pre-enc thread as of now SCD handling is not present */
//if(!(is_scd_ref_frame || ps_rc_ctxt->i4_is_pause_to_resume) || call_type == PRE_ENC_GET_QP)
{
WORD32 i4_is_first_frame_coded;
/*Once first frame has been encoded use prev frame intra satd and cur frame satd to alter est intra sad for cur frame*/
i4_is_first_frame_coded = is_first_frame_coded(ps_rc_ctxt->rc_hdl);
{
int i;
WORD32 i4_curr_bits_estimated, i4_is_model_valid;
/*initialise the coeffs to 1 and 0in case lap is not used */
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->af_sum_weigh[0][i][0] = 1.0;
ps_rc_ctxt->af_sum_weigh[0][i][1] = 0.0;
}
i4_frame_qp_q6 = get_frame_level_qp(
ps_rc_ctxt->rc_hdl,
rc_pic_type,
i4_max_frame_bits,
&i4_cur_est_texture_bits, //this value is returned by rc
ps_rc_ctxt->af_sum_weigh[0],
0,
8.0f,
NULL,
ps_rc_ctxt->i4_complexity_bin,
ps_rc_ctxt->i4_scene_num_latest, /*no pause resume concept*/
&i4_curr_bits_estimated,
&i4_is_model_valid,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
/** The usage of global table will truncate the input given as qp format and hence will not return very low qp values desirable at very
low bitrate. Hence on the fly calculation is enabled*/
i4_hevc_frame_qp =
ihevce_rc_get_scaled_hevce_qp_q6(i4_frame_qp_q6, ps_rc_ctxt->u1_bit_depth);
if(rc_pic_type == I_PIC)
{
/*scene cut handling during pre-enc stage*/
i4_frame_qp = rc_get_bpp_based_scene_cut_qp(
ps_rc_ctxt->rc_hdl,
rc_pic_type,
((3 * ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width) >> 1),
ps_rc_ctxt->ai4_lap_f_sim[0],
ps_rc_ctxt->af_sum_weigh[0],
0);
*pi4_scd_qp = ihevce_rc_get_scaled_hevc_qp_from_qs_q3(
i4_frame_qp << QSCALE_Q_FAC_3, ps_rc_ctxt->ps_rc_quant_ctxt);
*pi4_scd_qp = *pi4_scd_qp + ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset;
if(*pi4_scd_qp > ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qp)
*pi4_scd_qp = ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qp;
}
else
{
/*scene cut qp is only valid when queried for I_PIC*/
*pi4_scd_qp = i4_hevc_frame_qp;
}
}
}
ASSERT(i4_hevc_frame_qp >= (-ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset));
/*constraint qp swing based on neighbour frames*/
if(is_first_frame_coded(ps_rc_ctxt->rc_hdl))
{
if(ps_rc_ctxt->i4_field_pic == 0)
{
if((rc_pic_type != I_PIC && rc_pic_type != P_PIC) &&
i4_hevc_frame_qp >
ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[rc_pic_type - 1] +
3)
{
/*allow max of +3 compared to previous frame*/
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[rc_pic_type - 1] +
3;
}
if((rc_pic_type != I_PIC && rc_pic_type != P_PIC) &&
i4_hevc_frame_qp <
(ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[rc_pic_type - 1]))
{
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[rc_pic_type - 1];
}
/** Force non-ref B pic qp to be ref_B_PIC_qp - 1. This is not valid for when max teporla later is less than 2*/
if(i4_temporal_layer_id == ps_rc_ctxt->i4_max_temporal_lyr &&
ps_rc_ctxt->i4_max_temporal_lyr > 1)
{
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[rc_pic_type - 1] +
1;
}
}
else /*for field case*/
{
if(i4_temporal_layer_id >= 1)
{
/*To make the comparison of qp with the top field's of previous layer tempor layer id matches with the pic type. */
if(i4_hevc_frame_qp >
ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[i4_temporal_layer_id] +
3)
{
/*allow max of +3 compared to previous frame*/
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[i4_temporal_layer_id] +
3;
}
if(i4_hevc_frame_qp <
ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[i4_temporal_layer_id])
{
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[i4_temporal_layer_id];
}
/** Force non-ref B pic qp to be ref_B_PIC_qp - 1. This is not valid for when max teporla later is less than 2*/
if(i4_temporal_layer_id == ps_rc_ctxt->i4_max_temporal_lyr &&
ps_rc_ctxt->i4_max_temporal_lyr > 1)
{
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[ps_rc_ctxt->i4_scene_num_latest]
[i4_temporal_layer_id] +
1;
}
}
}
}
#if USE_USER_FIRST_FRAME_QP
/*I_PIC check is necessary coz pre-enc can query for qp even before first frame update has happened*/
if(!ps_rc_ctxt->i4_is_first_frame_encoded && rc_pic_type == I_PIC)
{
i4_hevc_frame_qp = ps_rc_ctxt->i4_init_frame_qp_user;
DBG_PRINTF("FIXED START QP PATH *************************\n");
}
#endif
/**clip to min qp which is user configurable*/
i4_hevc_frame_qp =
ihevce_clip_min_max_qp(ps_rc_ctxt, i4_hevc_frame_qp, rc_pic_type, i4_temporal_layer_id);
return i4_hevc_frame_qp;
}
}
/**
******************************************************************************
*
* @name ihevce_rc_cal_pre_enc_qp
*
* @par Description - Called from enc_loop_init. updates frame qp which will
be used by next frame of same pic type in pre-enc stage
*
* @param[in] ps_rc_ctxt - pointer to rc context
* @return void
*
******************************************************************************
*/
void ihevce_rc_cal_pre_enc_qp(void *pv_rc_ctxt)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
WORD32 i, i4_frame_qp, i4_scd_qp;
WORD32 i4_delay_l0_enc = 0;
i4_delay_l0_enc = ps_rc_ctxt->i4_pre_enc_rc_delay;
if(ps_rc_ctxt->e_rate_control_type != CONST_QP)
{
//DBG_PRINTF("\ncheck query read = %d write = %d",ps_rc_ctxt->i4_pre_enc_qp_read_index,ps_rc_ctxt->i4_pre_enc_qp_write_index);
#if DETERMINISTIC_RC
ASSERT(
ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_write_index].i4_is_qp_valid ==
-1);
#endif
for(i = 0; i < ps_rc_ctxt->i4_num_active_pic_type; i++)
{
i4_frame_qp =
ihevce_rc_get_pre_enc_pic_quant(ps_rc_ctxt, (picture_type_e)i, &i4_scd_qp);
ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_write_index].ai4_quant[i] =
i4_frame_qp;
/*returns valid scene cut qp only when queried as I_PIC*/
if(i == 0)
{
ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_write_index].i4_scd_qp =
i4_scd_qp;
}
if(ps_rc_ctxt->i4_field_pic && i > 0)
{
i4_frame_qp = ihevce_rc_get_pre_enc_pic_quant(
ps_rc_ctxt, (picture_type_e)(i + FIELD_OFFSET), &i4_scd_qp);
ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_write_index]
.ai4_quant[i + FIELD_OFFSET] = i4_frame_qp;
}
}
/*mark index as populated*/
ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_write_index].i4_is_qp_valid = 1;
ps_rc_ctxt->i4_pre_enc_qp_write_index =
(ps_rc_ctxt->i4_pre_enc_qp_write_index + 1) % i4_delay_l0_enc;
}
}
/**
******************************************************************************
*
* @brief function to get updated qp after L1 analysis for L0. '
* This uses estimated L0 satd based on L1 satd/act
*
* @par Description
*
* @param[in] pv_rc_ctxt
* void pointer to rc ctxt
* @param[in] rc_lap_out_params_t *
pointer to lap out structure
* @param[in] i8_est_L0_satd_act
* estimated L0 satd/act based on L1 satd/act
* @return void
*
******************************************************************************
*/
WORD32 ihevce_get_L0_est_satd_based_scd_qp(
void *pv_rc_ctxt,
rc_lap_out_params_t *ps_rc_lap_out,
LWORD64 i8_est_L0_satd_act,
float i_to_avg_rest_ratio)
{
rc_context_t *ps_ctxt = (rc_context_t *)pv_rc_ctxt;
WORD32 i4_frame_qs_q3, i4_hevc_qp, i4_est_header_bits, index, i, i4_total_bits;
picture_type_e rc_pic_type;
rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_rc_lap_out->i4_rc_pic_type,
ps_ctxt->i4_field_pic,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_lap_out->i4_is_bottom_field,
ps_ctxt->i4_top_field_first);
/*initialise the coeffs to 1 in case lap is not used */
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_ctxt->af_sum_weigh[0][i][0] = 1.0;
ps_ctxt->af_sum_weigh[0][i][1] = 0.0;
}
/*get bits to find estimate of header bits*/
i4_est_header_bits = rc_get_scene_change_est_header_bits(
ps_ctxt->rc_hdl,
ps_rc_lap_out->i4_num_pels_in_frame_considered,
ps_ctxt->ai4_lap_f_sim[0],
ps_ctxt->af_sum_weigh[0],
i_to_avg_rest_ratio);
index = ihevce_get_offline_index(ps_ctxt, ps_rc_lap_out->i4_num_pels_in_frame_considered);
{
WORD32 i4_true_scd = 0;
WORD32 i4_curr_bits_estimated;
i4_frame_qs_q3 = rc_get_qp_for_scd_frame(
ps_ctxt->rc_hdl,
I_PIC,
i8_est_L0_satd_act,
ps_rc_lap_out->i4_num_pels_in_frame_considered,
i4_est_header_bits,
ps_ctxt->ai4_lap_f_sim[0],
(void *)&g_offline_i_model_coeff[index][0],
i_to_avg_rest_ratio,
i4_true_scd,
ps_ctxt->af_sum_weigh[0],
ps_rc_lap_out->ps_frame_info,
ps_ctxt->i4_rc_pass,
0,
0,
0,
&i4_total_bits,
&i4_curr_bits_estimated,
ps_rc_lap_out->i4_use_offline_model_2pass,
0,
0,
-1,
NULL);
}
i4_hevc_qp = ihevce_rc_get_scaled_hevc_qp_from_qs_q3(i4_frame_qs_q3, ps_ctxt->ps_rc_quant_ctxt);
i4_hevc_qp = i4_hevc_qp + ps_ctxt->ps_rc_quant_ctxt->i1_qp_offset;
if(i4_hevc_qp > ps_ctxt->ps_rc_quant_ctxt->i2_max_qp)
i4_hevc_qp = ps_ctxt->ps_rc_quant_ctxt->i2_max_qp;
if(i4_hevc_qp < (SCD_MIN_HEVC_QP -
ps_ctxt->ps_rc_quant_ctxt
->i1_qp_offset)) // since outside RC the QP range is -12 to 51 for 10 bit
{
i4_hevc_qp = (SCD_MIN_HEVC_QP - ps_ctxt->ps_rc_quant_ctxt->i1_qp_offset);
}
else if(i4_hevc_qp > SCD_MAX_HEVC_QP)
{
i4_hevc_qp = SCD_MAX_HEVC_QP;
}
/*this is done outside loop*/
return i4_hevc_qp;
}
/**
******************************************************************************
*
* @name ihevce_rc_pre_enc_qp_query
*
* @par Description - Called from pre enc thrd for getting the qp of non scd
frames. updates frame qp from reverse queue from enc loop
when its available
*
* @param[in] ps_rc_ctxt - pointer to rc context
* @param[in] i4_update_delay : The Delay in the update. This can happen for dist. case!
* All decision should consider this delay for updation!
*
* @return void
*
******************************************************************************
*/
WORD32 ihevce_rc_pre_enc_qp_query(
void *pv_rc_ctxt, rc_lap_out_params_t *ps_rc_lap_out, WORD32 i4_update_delay)
{
WORD32 scene_type, i4_is_scd = 0, i4_frame_qp, slice_type;
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
rc_type_e e_rc_type = ps_rc_ctxt->e_rate_control_type;
IV_PICTURE_CODING_TYPE_T pic_type = (IV_PICTURE_CODING_TYPE_T)ps_rc_lap_out->i4_rc_pic_type;
picture_type_e rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_rc_lap_out->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
WORD32 i4_use_offset_flag = 0, k = 0;
WORD32 i4_inter_frame_interval = rc_get_inter_frame_interval(ps_rc_ctxt->rc_hdl);
WORD32 ai4_offsets[5] = { 0, 1, 2, 3, 4 };
rc_lap_out_params_t *ps_rc_lap_out_temp = ps_rc_lap_out;
/* The window for which your update is guaranteed */
WORD32 updated_window = ps_rc_ctxt->i4_num_frame_in_lap_window - i4_update_delay;
k = 0;
if((updated_window >= i4_inter_frame_interval) && (ps_rc_ctxt->i4_rc_pass != 2) &&
((rc_pic_type == I_PIC) || (rc_pic_type == P_PIC)))
{
WORD32 i4_count = 0;
for(i4_count = 0; i4_count < updated_window; i4_count++)
{
picture_type_e rc_pic_type_temp = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_rc_lap_out_temp->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_lap_out_temp->i4_rc_temporal_lyr_id,
ps_rc_lap_out_temp->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
if((rc_pic_type_temp == I_PIC) || (rc_pic_type_temp == P_PIC))
ihevce_compute_temporal_complexity_reset_Kp_Kb(ps_rc_lap_out_temp, pv_rc_ctxt, 0);
ps_rc_lap_out_temp =
(rc_lap_out_params_t *)ps_rc_lap_out_temp->ps_rc_lap_out_next_encode;
if(ps_rc_lap_out_temp == NULL)
break;
}
}
if(updated_window >= i4_inter_frame_interval)
{
i4_use_offset_flag = 1;
memmove(ai4_offsets, ps_rc_lap_out->ai4_offsets, sizeof(WORD32) * 5);
}
if(CONST_QP == e_rc_type)
{
switch(pic_type)
{
case IV_I_FRAME:
case IV_IDR_FRAME:
{
slice_type = ISLICE;
break;
}
case IV_P_FRAME:
{
slice_type = PSLICE;
break;
}
case IV_B_FRAME:
{
slice_type = BSLICE;
break;
}
}
i4_frame_qp = ihevce_get_cur_frame_qp(
ps_rc_ctxt->i4_init_frame_qp_user,
slice_type,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_ctxt->i4_min_frame_qp,
ps_rc_ctxt->i4_max_frame_qp,
ps_rc_ctxt->ps_rc_quant_ctxt);
return i4_frame_qp;
}
else
{
/*check scene type*/
scene_type = ihevce_rc_lap_get_scene_type(ps_rc_lap_out);
if(scene_type == SCENE_TYPE_SCENE_CUT)
{
i4_is_scd = 1;
ps_rc_ctxt->i4_num_frms_from_reset = 0;
#if USE_QP_OFFSET_POST_SCD
ps_rc_ctxt->i4_use_qp_offset_pre_enc = 1;
#else
ps_rc_ctxt->i4_use_qp_offset_pre_enc = 0;
#endif
}
ASSERT(
ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_read_index].i4_is_qp_valid ==
1 ||
ps_rc_lap_out->i4_rc_poc < 20);
if(ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_read_index].i4_is_qp_valid ==
1)
{
if(i4_is_scd || ps_rc_ctxt->i4_use_qp_offset_pre_enc)
{
#if 1 //The qp will be populated assuming the frame is I_PIC. Adjust according to current pic type
i4_frame_qp =
ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_read_index].i4_scd_qp;
if(rc_pic_type == P_PIC)
i4_frame_qp++;
else
i4_frame_qp = i4_frame_qp + ps_rc_lap_out->i4_rc_temporal_lyr_id;
#endif
if(i4_use_offset_flag)
{
if(rc_pic_type > B2_PIC)
i4_frame_qp = ps_rc_ctxt->i4_L0_frame_qp + ai4_offsets[rc_pic_type - 4];
else
i4_frame_qp = ps_rc_ctxt->i4_L0_frame_qp + ai4_offsets[rc_pic_type];
}
}
else
{
#if DETERMINISTIC_RC
i4_frame_qp = ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_read_index]
.ai4_quant[rc_pic_type];
#else
/*read the latest qp updated by enc*/
i4_frame_qp =
ps_rc_ctxt
->as_pre_enc_qp_queue
[(ps_rc_ctxt->i4_pre_enc_qp_write_index + MAX_PRE_ENC_RC_DELAY - 1) %
MAX_PRE_ENC_RC_DELAY]
.ai4_quant[rc_pic_type];
#endif
}
ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_read_index].i4_is_qp_valid =
-1;
/*once encoder starts reading from qp queue it should always read from qp queue*/
//ps_rc_ctxt->i4_use_init_qp_for_pre_enc = 0;
}
else
{
i4_frame_qp = ps_rc_ctxt->ai4_init_pre_enc_qp[rc_pic_type];
}
{
WORD32 i4_delay_l0_enc = ps_rc_ctxt->i4_pre_enc_rc_delay;
ps_rc_ctxt->i4_pre_enc_qp_read_index =
(ps_rc_ctxt->i4_pre_enc_qp_read_index + 1) % i4_delay_l0_enc;
if(ps_rc_ctxt->i4_num_frms_from_reset < i4_delay_l0_enc)
{
ps_rc_ctxt->i4_num_frms_from_reset++;
if(ps_rc_ctxt->i4_num_frms_from_reset >= i4_delay_l0_enc)
ps_rc_ctxt->i4_use_qp_offset_pre_enc = 0;
}
}
i4_frame_qp = CLIP3(i4_frame_qp, ps_rc_ctxt->i4_min_frame_qp, ps_rc_ctxt->i4_max_frame_qp);
return i4_frame_qp;
}
}
/**
******************************************************************************
*
* @brief function to estimate L0 satd based on L1 satd. '
*
*
* @par Description
*
* @param[in] pv_rc_ctxt
* void pointer to rc ctxt
* @param[in] rc_lap_out_params_t *
pointer to lap out structure
* @param[in] i8_est_L0_satd_act
* estimated L0 satd/act based on L1 satd/act
* @return void
*
******************************************************************************
*/
LWORD64 ihevce_get_L0_satd_based_on_L1(
LWORD64 i8_satd_by_act_L1, WORD32 i4_num_pixel, WORD32 i4_cur_q_scale)
{
LWORD64 est_L0_satd_by_act;
float m, c;
/** choose coeff based on resolution*/
if(i4_num_pixel > 5184000)
{
m = (float)2.3911;
c = (float)86329;
}
else if(i4_num_pixel > 1497600)
{
m = (float)2.7311;
c = (float)-1218.9;
}
else if(i4_num_pixel > 633600)
{
m = (float)3.1454;
c = (float)-5836.1;
}
else
{
m = (float)3.5311;
c = (float)-2377.2;
}
/*due to qp difference between I and P, For P pic for same */
est_L0_satd_by_act = (LWORD64)(i8_satd_by_act_L1 / i4_cur_q_scale * m + c) * i4_cur_q_scale;
{
if(est_L0_satd_by_act < (i4_num_pixel >> 3))
est_L0_satd_by_act = (i4_num_pixel >> 3);
}
return est_L0_satd_by_act;
}
/**
******************************************************************************
*
* @name ihevce_rc_register_L1_analysis_data
*
* @par Description
*
* @param[in] ps_rc_ctxt - pointer to rc context
* ps_rc_lap_out
* i8_est_L0_satd_by_act
* i8_pre_intra_sad
* i8_l1_hme_sad
* @return void
*
******************************************************************************
*/
void ihevce_rc_register_L1_analysis_data(
void *pv_rc_ctxt,
rc_lap_out_params_t *ps_rc_lap_out,
LWORD64 i8_est_L0_satd_by_act,
LWORD64 i8_pre_intra_sad,
LWORD64 i8_l1_hme_sad)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
WORD32 i, data_available = 1;
picture_type_e rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_rc_lap_out->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
//if( ps_rc_ctxt->u4_rc_scene_num_est_L0_intra_sad_available == ps_rc_lap_out->u4_rc_scene_num)
{
/*update current frame's data*/
ps_rc_ctxt->ai8_prev_frame_est_L0_satd[rc_pic_type] = i8_est_L0_satd_by_act;
ps_rc_ctxt->ai8_prev_frame_hme_sad[rc_pic_type] = i8_l1_hme_sad;
ps_rc_ctxt->ai8_prev_frame_pre_intra_sad[rc_pic_type] = i8_pre_intra_sad;
}
/*check if data is available for all picture type*/
if(!ps_rc_ctxt->i4_is_est_L0_intra_sad_available)
{
for(i = 0; i < ps_rc_ctxt->i4_num_active_pic_type; i++)
{
data_available &= (ps_rc_ctxt->ai8_prev_frame_est_L0_satd[i] >= 0);
if(ps_rc_ctxt->i4_field_pic == 1 && i != 0)
data_available &= (ps_rc_ctxt->ai8_prev_frame_est_L0_satd[i + FIELD_OFFSET] >= 0);
}
ps_rc_ctxt->i4_is_est_L0_intra_sad_available = data_available;
}
}
/*#######################################################*/
/******* END OF PRE-ENC QP QUERY FUNCTIONS **************/
/*#####################################################*/
/*##########################################################*/
/******* START OF ENC THRD QP QUERY FUNCTIONS **************/
/*########################################################*/
/**
******************************************************************************
*
* @brief function to get ihevce_rc_get_pic_quant
*
* @par Description
* @param[in] i4_update_delay : The Delay in the update. This can happen for dist. case!
* All decision should consider this delay for updation!
******************************************************************************
*/
WORD32 ihevce_rc_get_pic_quant(
void *pv_ctxt,
rc_lap_out_params_t *ps_rc_lap_out,
IHEVCE_RC_CALL_TYPE call_type,
WORD32 i4_enc_frm_id,
WORD32 i4_update_delay,
WORD32 *pi4_tot_bits_estimated)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
WORD32 i4_frame_qp, i4_frame_qp_q6, i4_hevc_frame_qp = -1, i4_deltaQP = 0;
WORD32 i4_max_frame_bits = (1 << 30);
rc_type_e e_rc_type = ps_rc_ctxt->e_rate_control_type;
WORD32 slice_type, index, i4_num_frames_in_cur_gop, i4_cur_est_texture_bits;
WORD32 temporal_layer_id = ps_rc_lap_out->i4_rc_temporal_lyr_id;
IV_PICTURE_CODING_TYPE_T pic_type = (IV_PICTURE_CODING_TYPE_T)ps_rc_lap_out->i4_rc_pic_type;
picture_type_e rc_pic_type = ihevce_rc_conv_pic_type(
pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
float i_to_avg_bit_ratio;
frame_info_t s_frame_info_temp;
WORD32 i4_scene_num = ps_rc_lap_out->u4_rc_scene_num % MAX_SCENE_NUM;
WORD32 i4_vbv_buf_max_bits;
WORD32 i4_est_tex_bits;
WORD32 i4_cur_est_header_bits, i4_fade_scene;
WORD32 i4_model_available, i4_is_no_model_scd;
WORD32 i4_estimate_to_calc_frm_error;
/* The window for which your update is guaranteed */
WORD32 updated_window = ps_rc_ctxt->i4_num_frame_in_lap_window - i4_update_delay;
ps_rc_ctxt->i4_scene_num_latest = i4_scene_num;
ps_rc_ctxt->s_rc_high_lvl_stat.i4_modelQP = INVALID_QP;
ps_rc_ctxt->s_rc_high_lvl_stat.i4_finalQP = INVALID_QP;
ps_rc_ctxt->s_rc_high_lvl_stat.i4_maxEbfQP = INVALID_QP;
ps_rc_ctxt->i4_quality_preset = ps_rc_lap_out->i4_rc_quality_preset;
ps_rc_ctxt->s_rc_high_lvl_stat.i4_finalQP = INVALID_QP;
if(1 == ps_rc_ctxt->i4_bitrate_changed)
{
ps_rc_ctxt->i4_bitrate_changed = 0;
}
if(CONST_QP == e_rc_type)
{
switch(pic_type)
{
case IV_I_FRAME:
case IV_IDR_FRAME:
{
slice_type = ISLICE;
break;
}
case IV_P_FRAME:
{
slice_type = PSLICE;
break;
}
case IV_B_FRAME:
{
slice_type = BSLICE;
break;
}
}
i4_frame_qp = ihevce_get_cur_frame_qp(
ps_rc_ctxt->i4_init_frame_qp_user,
slice_type,
temporal_layer_id,
ps_rc_ctxt->i4_min_frame_qp,
ps_rc_ctxt->i4_max_frame_qp,
ps_rc_ctxt->ps_rc_quant_ctxt);
return i4_frame_qp;
}
else
{
WORD32 is_scd_ref_frame = 0, i4_num_scd_in_lap_window = 0, num_frames_b4_scd = 0,
scene_type = 0, i;
//ihevce_lap_output_params_t *ps_cur_rc_lap_out;
if(ps_rc_ctxt->ai4_scene_num_last_pic[rc_pic_type] !=
(WORD32)ps_rc_lap_out->u4_rc_scene_num)
{
rc_reset_pic_model(ps_rc_ctxt->rc_hdl, rc_pic_type);
rc_reset_first_frame_coded_flag(ps_rc_ctxt->rc_hdl, rc_pic_type);
}
ps_rc_ctxt->ai4_scene_num_last_pic[rc_pic_type] = ps_rc_lap_out->u4_rc_scene_num;
if(call_type == ENC_GET_QP)
{
i4_model_available = model_availability(ps_rc_ctxt->rc_hdl, rc_pic_type);
ps_rc_lap_out->i8_est_text_bits = -1;
}
if((rc_pic_type == I_PIC) || (rc_pic_type == P_PIC) || (rc_pic_type == P1_PIC))
{
ps_rc_ctxt->i4_cur_scene_num = ps_rc_lap_out->u4_rc_scene_num;
}
{
if(!(pic_type == IV_I_FRAME || pic_type == IV_IDR_FRAME))
{
ps_rc_ctxt->ai8_cur_frame_coarse_ME_cost[i4_enc_frm_id] =
ps_rc_lap_out->i8_frame_acc_coarse_me_cost;
}
/*check if frame is scene cut*/
/* If scd do not query the model. obtain qp from offline data model*/
scene_type = ihevce_rc_lap_get_scene_type(ps_rc_lap_out);
if(ps_rc_ctxt->ai4_scene_numbers[ps_rc_lap_out->u4_rc_scene_num] == 0 &&
(scene_type != SCENE_TYPE_SCENE_CUT))
{
scene_type = SCENE_TYPE_SCENE_CUT;
}
if(ps_rc_ctxt->ai4_scene_numbers[ps_rc_lap_out->u4_rc_scene_num] > 0 &&
(scene_type == SCENE_TYPE_SCENE_CUT))
{
scene_type = SCENE_TYPE_NORMAL;
}
if(scene_type == SCENE_TYPE_SCENE_CUT)
{
if((ps_rc_lap_out->i4_rc_quality_preset == IHEVCE_QUALITY_P6) &&
(rc_pic_type > P_PIC))
{
is_scd_ref_frame = 0;
}
else
{
is_scd_ref_frame = 1;
}
}
else if(scene_type == SCENE_TYPE_PAUSE_TO_RESUME)
{
/*pause to resume flag will only be set in layer 0 frames( I and P pic)*/
/*I PIC can handle this by detecting I_only SCD which is based on open loop SATD hence explicit handling for pause to resume is required only for P_PIC*/
if(ps_rc_lap_out->i4_rc_quality_preset == IHEVCE_QUALITY_P6)
{
if(call_type == ENC_GET_QP && rc_pic_type == P_PIC)
{
ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id] = 1;
}
}
else
{
if(call_type == ENC_GET_QP && rc_pic_type != I_PIC)
{
ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id] = 1;
}
}
}
ps_rc_ctxt->ai4_is_cmplx_change_reset_model[i4_enc_frm_id] =
ps_rc_lap_out->i4_is_cmplx_change_reset_model;
ps_rc_ctxt->ai4_is_cmplx_change_reset_bits[i4_enc_frm_id] =
ps_rc_lap_out->i4_is_cmplx_change_reset_bits;
/*initialise the coeffs to 1 in case lap is not used */
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][i][0] = 1.0;
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][i][1] = 0.0;
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][i][2] = 0.0;
}
/*treat even first frame as scd frame*/
if(!ps_rc_ctxt->i4_is_first_frame_encoded)
{
is_scd_ref_frame = 1;
}
/*special case SCD handling for Non-I pic*/
if(!(pic_type == IV_I_FRAME || pic_type == IV_IDR_FRAME) && call_type == ENC_GET_QP)
{
if(is_scd_ref_frame)
{
/*A non-I pic will only be marked as scene cut only if there is another SCD follows within another subgop*/
ps_rc_ctxt->ai4_is_non_I_scd_pic[i4_enc_frm_id] = 1;
}
/*check if current sad is very different from previous SAD and */
else if(
!ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id] &&
ps_rc_lap_out->i4_is_non_I_scd)
{
ps_rc_ctxt->ai4_is_non_I_scd_pic[i4_enc_frm_id] = 1;
is_scd_ref_frame = 1;
}
}
if(call_type == PRE_ENC_GET_QP)
{
/*Only I frames are considered as scd pic during pre-enc*/
is_scd_ref_frame &= (pic_type == IV_I_FRAME || pic_type == IV_IDR_FRAME);
}
/*special case SCD handling for I pic*/
if((pic_type == IV_I_FRAME || pic_type == IV_IDR_FRAME) && !is_scd_ref_frame)
{
/*If open loop SATD's of two I picture are very different then treat the I pic as SCD and reset only model as this can
happen during fade-in and fade-out where other picture types would have learnt. Reset is required only for I.*/
if(ps_rc_lap_out->i4_is_I_only_scd)
{
is_scd_ref_frame = 1;
ps_rc_ctxt->ai4_I_model_only_reset[i4_enc_frm_id] = 1;
}
}
/*should be recalculated for every picture*/
if((updated_window) > 0 && (call_type == ENC_GET_QP) && (ps_rc_ctxt->i4_rc_pass != 2))
{
rc_lap_out_params_t *ps_cur_rc_lap_out;
UWORD32 u4_L1_based_lap_complexity_q7;
WORD32 i = 0, k = 0, i4_f_sim = 0, i4_h_sim = 0, i4_var_sum = 0,
i4_num_pic_metric_count = 0, i4_is_first_frm = 1,
i4_intra_frame_interval = 0;
LWORD64 i8_l1_analysis_lap_comp = 0;
LWORD64 nor_frm_hme_sad_q10;
picture_type_e curr_rc_pic_type;
WORD32 ai4_pic_dist[MAX_PIC_TYPE] = { 0 };
LWORD64 i8_sad_first_frame_pic_type[MAX_PIC_TYPE] = { 0 },
i8_total_sad_pic_type[MAX_PIC_TYPE] = { 0 };
LWORD64 i8_last_frame_pic_type[MAX_PIC_TYPE] = { 0 }, i8_esti_consum_bits = 0;
WORD32 i4_num_pic_type[MAX_PIC_TYPE] = { 0 }, i4_frames_in_lap_end = 0,
i4_first_frame_coded_flag, i4_gop_end_flag = 1, i4_num_frame_for_ebf = 0;
i4_first_frame_coded_flag = is_first_frame_coded(ps_rc_ctxt->rc_hdl);
/*Setting the next scene cut as well as pic distribution for the gop*/
ps_cur_rc_lap_out = (rc_lap_out_params_t *)ps_rc_lap_out;
i4_intra_frame_interval = rc_get_intra_frame_interval(ps_rc_ctxt->rc_hdl);
/*Set the rc sc i next*/
if(ps_cur_rc_lap_out != NULL)
{
WORD32 i4_count = 0;
do
{
if(((rc_lap_out_params_t *)ps_cur_rc_lap_out->ps_rc_lap_out_next_encode ==
NULL)) //||((( (ihevce_lap_output_params_t*)ps_cur_rc_lap_out->ps_lap_out_next)->i8_pre_intra_sad == -1) || ( ((ihevce_lap_output_params_t*)ps_cur_rc_lap_out->ps_lap_out_next)->i8_raw_pre_intra_sad == -1) ||( ((ihevce_lap_output_params_t*)ps_cur_rc_lap_out->ps_lap_out_next)->i8_raw_l1_coarse_me_sad == -1) ||(((ihevce_lap_output_params_t*)ps_cur_rc_lap_out->ps_lap_out_next)->i8_frame_acc_coarse_me_sad == -1)))
break;
ps_cur_rc_lap_out =
(rc_lap_out_params_t *)ps_cur_rc_lap_out->ps_rc_lap_out_next_encode;
i4_count++;
} while((i4_count + 1) < updated_window);
rc_set_next_sc_i_in_rc_look_ahead(
ps_rc_ctxt->rc_hdl, ps_cur_rc_lap_out->i4_next_sc_i_in_rc_look_ahead);
rc_update_pic_distn_lap_to_rc(
ps_rc_ctxt->rc_hdl, ps_cur_rc_lap_out->ai4_num_pic_type);
ps_rc_ctxt->i4_next_sc_i_in_rc_look_ahead =
ps_cur_rc_lap_out->i4_next_sc_i_in_rc_look_ahead;
}
ps_cur_rc_lap_out = (rc_lap_out_params_t *)ps_rc_lap_out;
if(ps_cur_rc_lap_out != NULL)
{
/*initialise the coeffs to 1 in case lap is not used */
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][i][0] = 0.0;
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][i][1] = 0.0;
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][i][2] = 0.0;
}
i = 0;
k = 0;
//ASSERT(ps_cur_rc_lap_out != NULL);
do
{
curr_rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_cur_rc_lap_out->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_cur_rc_lap_out->i4_rc_temporal_lyr_id,
ps_cur_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
if(ps_rc_ctxt->i4_is_first_frame_encoded || !i4_is_first_frm)
{
/*Ignore first frame Fsim as it is not valid for first frame*/
i4_f_sim += ps_cur_rc_lap_out->s_pic_metrics.i4_fsim;
i4_h_sim += ps_cur_rc_lap_out->s_pic_metrics.ai4_hsim[0];
i4_var_sum += (WORD32)ps_cur_rc_lap_out->s_pic_metrics.i8_8x8_var_lum;
i4_num_pic_metric_count++;
//DBG_PRINTF("\n fsim = %d i = %d",ps_cur_rc_lap_out->s_pic_metrics.i4_fsim,i);
//ASSERT(ps_cur_rc_lap_out->s_pic_metrics.i4_fsim <= 128);
}
/*accumulate complexity from LAP2*/
if(curr_rc_pic_type == I_PIC)
{
i8_l1_analysis_lap_comp +=
(LWORD64)(1.17 * ps_cur_rc_lap_out->i8_raw_pre_intra_sad);
}
else
{
if(curr_rc_pic_type <= B2_PIC)
i8_l1_analysis_lap_comp += (LWORD64)(
(float)ps_cur_rc_lap_out->i8_raw_l1_coarse_me_sad /
pow(1.125f, curr_rc_pic_type));
else
i8_l1_analysis_lap_comp += (LWORD64)(
(float)ps_cur_rc_lap_out->i8_raw_l1_coarse_me_sad /
pow(1.125f, curr_rc_pic_type - B2_PIC));
}
i++;
i4_is_first_frm = 0;
/*CAll the function for predictting the ebf and stuffing condition check*/
/*rd model pass lapout l1 pass ebf return estimated ebf and signal*/
{
if(i4_first_frame_coded_flag && (i4_gop_end_flag != 0))
{
if(curr_rc_pic_type == 0)
i4_gop_end_flag = 0;
if(i4_gop_end_flag)
{
WORD32 prev_frm_cl_sad =
rc_get_prev_frame_sad(ps_rc_ctxt->rc_hdl, curr_rc_pic_type);
WORD32 cur_frm_est_cl_sad = (WORD32)(
(ps_cur_rc_lap_out->i8_frame_acc_coarse_me_cost *
prev_frm_cl_sad) /
ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[curr_rc_pic_type]);
i8_esti_consum_bits += bit_alloc_get_estimated_bits_for_pic(
ps_rc_ctxt->rc_hdl,
cur_frm_est_cl_sad,
prev_frm_cl_sad,
curr_rc_pic_type);
i4_num_frame_for_ebf++;
}
}
}
ps_cur_rc_lap_out =
(rc_lap_out_params_t *)ps_cur_rc_lap_out->ps_rc_lap_out_next_encode;
/*The scene cut is lap window other than current frame is used to reduce bit alloc window for I pic*/
if(ps_cur_rc_lap_out != NULL &&
ps_cur_rc_lap_out->i4_rc_scene_type == SCENE_TYPE_SCENE_CUT)
{
i4_num_scd_in_lap_window++;
if(i4_num_scd_in_lap_window == 1)
{
/*Note how many frames are parsed before first scd is hit*/
num_frames_b4_scd = i + 1;
}
}
if((ps_cur_rc_lap_out == NULL ||
(i >=
(updated_window -
k)))) //||((( -1 == ps_cur_rc_lap_out->i8_pre_intra_sad ) || ( -1 == ps_cur_rc_lap_out->i8_raw_pre_intra_sad ) ||( -1 == ps_cur_rc_lap_out->i8_raw_l1_coarse_me_sad) ||(-1 == ps_cur_rc_lap_out->i8_frame_acc_coarse_me_sad))))
break;
if(0) //(( -1 == ps_cur_rc_lap_out->i8_pre_intra_sad ) || ( -1 == ps_cur_rc_lap_out->i8_raw_pre_intra_sad ) ||( -1 == ps_cur_rc_lap_out->i8_raw_l1_coarse_me_sad) ||(-1 == ps_cur_rc_lap_out->i8_frame_acc_coarse_me_sad)))
{
k++;
ps_cur_rc_lap_out =
(rc_lap_out_params_t *)ps_cur_rc_lap_out->ps_rc_lap_out_next_encode;
if(ps_cur_rc_lap_out == NULL)
break;
continue;
}
} while(1);
;
}
/*For the first subgop we cant have underflow prevention logic
since once picture of each type is not encoded also happens for static contents thants high i_to avg_ratio */
if(i4_first_frame_coded_flag &&
(ps_rc_ctxt->ai_to_avg_bit_ratio[i4_enc_frm_id] > I_TO_REST_SLOW))
{
if(!(i4_num_frame_for_ebf < ps_rc_ctxt->i4_max_inter_frm_int))
rc_bit_alloc_detect_ebf_stuff_scenario(
ps_rc_ctxt->rc_hdl,
i4_num_frame_for_ebf,
i8_esti_consum_bits,
ps_rc_ctxt->i4_max_inter_frm_int);
}
k = 0;
i4_frames_in_lap_end = 0;
{
rc_lap_out_params_t *ps_cur_rc_lap_out1;
ps_cur_rc_lap_out1 = (rc_lap_out_params_t *)ps_rc_lap_out;
do
{
curr_rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_cur_rc_lap_out1->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_cur_rc_lap_out1->i4_rc_temporal_lyr_id,
ps_cur_rc_lap_out1->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
/*accumulate complexity from LAP2*/
if(curr_rc_pic_type == I_PIC)
{
i8_total_sad_pic_type[I_PIC] +=
ps_cur_rc_lap_out1->i8_raw_pre_intra_sad;
i8_last_frame_pic_type[I_PIC] =
ps_cur_rc_lap_out1->i8_raw_pre_intra_sad;
}
else
{
i8_total_sad_pic_type[curr_rc_pic_type] +=
ps_cur_rc_lap_out1->i8_raw_l1_coarse_me_sad;
i8_last_frame_pic_type[curr_rc_pic_type] =
ps_cur_rc_lap_out1->i8_raw_l1_coarse_me_sad;
}
if(i4_num_pic_type[curr_rc_pic_type] == 0)
{
if(curr_rc_pic_type == I_PIC)
{
i8_sad_first_frame_pic_type[I_PIC] =
ps_cur_rc_lap_out1->i8_raw_pre_intra_sad;
}
else
{
i8_sad_first_frame_pic_type[curr_rc_pic_type] =
ps_cur_rc_lap_out1->i8_raw_l1_coarse_me_sad;
}
}
i4_num_pic_type[curr_rc_pic_type]++;
i4_frames_in_lap_end++;
ps_cur_rc_lap_out1 =
(rc_lap_out_params_t *)ps_cur_rc_lap_out1->ps_rc_lap_out_next_encode;
if((ps_cur_rc_lap_out1 == NULL ||
(i4_frames_in_lap_end >=
(updated_window -
k)))) //||((( -1 == ps_cur_rc_lap_out1->i8_pre_intra_sad ) || ( -1 == ps_cur_rc_lap_out1->i8_raw_pre_intra_sad ) ||( -1 == ps_cur_rc_lap_out1->i8_raw_l1_coarse_me_sad) ||(-1 == ps_cur_rc_lap_out1->i8_frame_acc_coarse_me_sad))))
{
break;
}
if(0) //((( -1 == ps_cur_rc_lap_out1->i8_pre_intra_sad ) || ( -1 == ps_cur_rc_lap_out1->i8_raw_pre_intra_sad ) ||( -1 == ps_cur_rc_lap_out1->i8_raw_l1_coarse_me_sad) ||(-1 == ps_cur_rc_lap_out1->i8_frame_acc_coarse_me_sad))))
{
k++;
ps_cur_rc_lap_out1 = (rc_lap_out_params_t *)
ps_cur_rc_lap_out1->ps_rc_lap_out_next_encode;
if(ps_cur_rc_lap_out1 == NULL)
break;
continue;
}
} while(i4_frames_in_lap_end < (ps_rc_ctxt->i4_next_sc_i_in_rc_look_ahead - k));
}
/*get picture type distribution in LAP*/
rc_get_pic_distribution(ps_rc_ctxt->rc_hdl, &ai4_pic_dist[0]);
{
float f_prev_comp;
WORD32 j;
float af_sum_weigh[MAX_PIC_TYPE], af_nume_weight[MAX_PIC_TYPE];
float af_average_sad_pic_type[MAX_PIC_TYPE] = { 0 };
for(j = 0; j < MAX_PIC_TYPE; j++)
{
if(i4_num_pic_type[j] > 0)
{
af_average_sad_pic_type[j] =
(float)i8_total_sad_pic_type[j] / i4_num_pic_type[j];
}
f_prev_comp = 1.;
i4_num_pic_type[j] = (i4_num_pic_type[j] > ai4_pic_dist[j])
? ai4_pic_dist[j]
: i4_num_pic_type[j];
af_sum_weigh[j] = (float)i4_num_pic_type[j];
af_nume_weight[j] = 1.0;
if(i4_num_pic_type[j] > 1 && (af_average_sad_pic_type[j] > 0))
{
af_nume_weight[j] =
(float)i8_sad_first_frame_pic_type[j] / af_average_sad_pic_type[j];
f_prev_comp =
(float)i8_last_frame_pic_type[j] / af_average_sad_pic_type[j];
}
//if(rc_pic_type != I_PIC)
{
af_sum_weigh[j] += f_prev_comp * (ai4_pic_dist[j] - i4_num_pic_type[j]);
}
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][j][0] = af_nume_weight[j];
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][j][1] = af_sum_weigh[j];
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][j][2] = af_average_sad_pic_type[j];
/*Disabling steady state complexity based bit movement*/
/*Enable it in CBR and not in VBR since VBR already has complexity based bit movement*/
if(0) /*i4_frames_in_lap_end < (updated_window) || ps_rc_ctxt->e_rate_control_type == VBR_STREAMING)*/
{
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][j][0] = 1.0;
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id][j][1] =
0; //(float)ai4_pic_dist[j];
}
}
memmove(
ps_rc_lap_out->ps_frame_info->af_sum_weigh,
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id],
sizeof(float) * MAX_PIC_TYPE * 3);
}
if(i4_num_pic_metric_count > 0)
{
i4_f_sim = i4_f_sim / i4_num_pic_metric_count;
i4_h_sim = i4_h_sim / i4_num_pic_metric_count;
i4_var_sum = i4_var_sum / i4_num_pic_metric_count;
}
else
{
i4_f_sim = MODERATE_FSIM_VALUE;
i4_h_sim = MODERATE_FSIM_VALUE;
}
if(i > 0)
{
float lap_L1_comp =
(float)i8_l1_analysis_lap_comp /
(i * ps_rc_ctxt->i4_frame_height *
ps_rc_ctxt->i4_frame_width); //per frame per pixel complexity
lap_L1_comp = rc_get_offline_normalized_complexity(
ps_rc_ctxt->u4_intra_frame_interval,
ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width,
lap_L1_comp,
ps_rc_ctxt->i4_rc_pass);
u4_L1_based_lap_complexity_q7 = (WORD32)((lap_L1_comp * (1 << 7)) + .05f);
}
else
{
u4_L1_based_lap_complexity_q7 = 25;
}
ps_rc_ctxt->ai4_lap_complexity_q7[i4_enc_frm_id] =
(WORD32)u4_L1_based_lap_complexity_q7;
/*clip f_sim to 0.3 for better stability*/
if(i4_f_sim < 38)
i4_f_sim = 128 - MAX_LAP_COMPLEXITY_Q7;
ps_rc_ctxt->ai4_lap_f_sim[i4_enc_frm_id] = i4_f_sim;
/*calculate normalized per pixel sad*/
nor_frm_hme_sad_q10 = (ps_rc_lap_out->i8_frame_acc_coarse_me_cost << 10) /
(ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width);
/*if(rc_pic_type == P_PIC)
DBG_PRINTF("\n P frm hme sad = %f ",((float)nor_frm_hme_sad_q10/ (1 << 10))); */
rc_put_temp_comp_lap(
ps_rc_ctxt->rc_hdl, i4_f_sim, nor_frm_hme_sad_q10, rc_pic_type);
rc_set_num_scd_in_lap_window(
ps_rc_ctxt->rc_hdl, i4_num_scd_in_lap_window, num_frames_b4_scd);
if(rc_pic_type == I_PIC && updated_window > (ps_rc_ctxt->i4_max_inter_frm_int << 1))
{
float i_to_avg_bit_ratio = ihevce_get_i_to_avg_ratio(
(void *)ps_rc_ctxt,
ps_rc_lap_out,
1,
1,
1,
ps_rc_lap_out->ai4_offsets,
i4_update_delay);
i_to_avg_bit_ratio = i_to_avg_bit_ratio * 1;
}
/* accumulation of the hme sad over next sub gop to find the temporal comlexity of the sub GOP*/
if((rc_pic_type == I_PIC) || (rc_pic_type == P_PIC))
{
ihevce_compute_temporal_complexity_reset_Kp_Kb(
ps_rc_lap_out, (void *)ps_rc_ctxt, 1);
}
if(i4_var_sum > MAX_LAP_VAR)
{
i4_var_sum = MAX_LAP_VAR;
}
{
/*Filling for dumping data */
ps_rc_ctxt->ai4_num_scd_in_lap_window[i4_enc_frm_id] = i4_num_scd_in_lap_window;
ps_rc_ctxt->ai4_num_frames_b4_scd[i4_enc_frm_id] = num_frames_b4_scd;
}
}
}
if((ps_rc_lap_out->i4_rc_quality_preset == IHEVCE_QUALITY_P6) && (rc_pic_type > P_PIC))
{
ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id] = 0;
is_scd_ref_frame = 0;
}
i4_fade_scene = 0;
/*Scene type fade is marked only for P pics which are in fade regions*/
if((ps_rc_lap_out->i4_rc_scene_type == SCENE_TYPE_FADE_IN ||
ps_rc_lap_out->i4_rc_scene_type == SCENE_TYPE_FADE_OUT) &&
(ps_rc_lap_out->i4_rc_temporal_lyr_id == 0))
{
is_scd_ref_frame = 1;
i4_fade_scene = 1;
}
if((!(is_scd_ref_frame || ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id])) &&
(((is_first_frame_coded(ps_rc_ctxt->rc_hdl)) && (pic_type == IV_I_FRAME)) ||
(pic_type != IV_I_FRAME)))
{
WORD32 i4_is_first_frame_coded = is_first_frame_coded(ps_rc_ctxt->rc_hdl);
i4_is_no_model_scd = 0;
if(call_type == ENC_GET_QP)
{
if(((0 == i4_model_available) || (!i4_is_first_frame_coded)))
{
/*No scene change but model not available*/
i4_is_no_model_scd = 1;
}
}
}
else
{
/*actual scene changes*/
i4_is_no_model_scd = 2;
}
/** Pre-enc thread as of now SCD handling is not present */
if(!i4_is_no_model_scd)
{
WORD32 i4_is_first_frame_coded, i4_prev_I_frm_sad, i4_cur_I_frm_sad;
/*Once first frame has been encoded use prev frame intra satd and cur frame satd to alter est intra sad for cur frame*/
i4_is_first_frame_coded = is_first_frame_coded(ps_rc_ctxt->rc_hdl);
/*prev I frame sad i changes only in enc stage. For pre enc cur and prev will be same*/
if(ps_rc_ctxt->i8_prev_i_frm_cost > 0)
{
if(i4_is_first_frame_coded && (pic_type == IV_I_FRAME || pic_type == IV_IDR_FRAME))
{
i4_prev_I_frm_sad = rc_get_prev_frame_intra_sad(ps_rc_ctxt->rc_hdl);
i4_cur_I_frm_sad = (WORD32)(
(ps_rc_ctxt->ai8_cur_frm_intra_cost[i4_enc_frm_id] * i4_prev_I_frm_sad) /
ps_rc_ctxt->i8_prev_i_frm_cost);
rc_update_prev_frame_intra_sad(ps_rc_ctxt->rc_hdl, i4_cur_I_frm_sad);
}
}
/*scale previous frame closed loop SAD with current frame HME SAD to be considered as current frame SAD*/
if(i4_is_first_frame_coded && !(pic_type == IV_I_FRAME || pic_type == IV_IDR_FRAME) &&
call_type == ENC_GET_QP)
{
if(ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[rc_pic_type] > 0)
{
WORD32 prev_frm_cl_sad = rc_get_prev_frame_sad(ps_rc_ctxt->rc_hdl, rc_pic_type);
WORD32 cur_frm_est_cl_sad = (WORD32)(
(ps_rc_ctxt->ai8_cur_frame_coarse_ME_cost[i4_enc_frm_id] *
prev_frm_cl_sad) /
ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[rc_pic_type]);
rc_update_prev_frame_sad(ps_rc_ctxt->rc_hdl, cur_frm_est_cl_sad, rc_pic_type);
}
}
if(rc_pic_type == I_PIC && updated_window > (ps_rc_ctxt->i4_max_inter_frm_int << 1))
{
ps_rc_ctxt->ai_to_avg_bit_ratio[i4_enc_frm_id] = ihevce_get_i_to_avg_ratio(
(void *)ps_rc_ctxt,
ps_rc_lap_out,
1,
0,
1,
ps_rc_lap_out->ai4_offsets,
i4_update_delay);
}
ps_rc_ctxt->s_rc_high_lvl_stat.i8_bits_from_finalQP = -1;
i4_frame_qp_q6 = get_frame_level_qp(
ps_rc_ctxt->rc_hdl,
rc_pic_type,
i4_max_frame_bits,
&i4_cur_est_texture_bits, //this value is returned by rc
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id],
1,
ps_rc_ctxt->ai_to_avg_bit_ratio[i4_enc_frm_id],
ps_rc_lap_out->ps_frame_info,
ps_rc_lap_out->i4_complexity_bin,
i4_scene_num, /*no pause resume concept*/
pi4_tot_bits_estimated,
&ps_rc_lap_out->i4_is_model_valid,
&i4_vbv_buf_max_bits,
&i4_est_tex_bits,
&i4_cur_est_header_bits,
&ps_rc_ctxt->s_rc_high_lvl_stat.i4_maxEbfQP,
&ps_rc_ctxt->s_rc_high_lvl_stat.i4_modelQP,
&i4_estimate_to_calc_frm_error);
ASSERT(*pi4_tot_bits_estimated != 0);
/** The usage of global table will truncate the input given as qp format and hence will not return very low qp values desirable at very
low bitrate. Hence on the fly calculation is enabled*/
i4_hevc_frame_qp =
ihevce_rc_get_scaled_hevce_qp_q6(i4_frame_qp_q6, ps_rc_ctxt->u1_bit_depth);
if(1 == ps_rc_lap_out->i4_is_model_valid)
ps_rc_lap_out->i4_is_steady_state = 1;
else
ps_rc_lap_out->i4_is_steady_state = 0;
ps_rc_ctxt->s_rc_high_lvl_stat.i4_is_offline_model_used = 0;
ps_rc_ctxt->i8_est_I_pic_header_bits = i4_cur_est_header_bits;
}
else
{
WORD32 i4_count = 0, i4_total_bits, i4_min_error_hevc_qp = 0;
float f_percent_error = 0.0f, f_min_error = 10000.0f;
WORD32 i4_current_bits_estimated = 0;
float i4_i_to_rest_ratio_final;
WORD32 i4_best_br_id = 0;
float af_i_qs[2];
LWORD64 ai8_i_tex_bits[2];
WORD32 i4_ref_qscale = ihevce_rc_get_scaled_mpeg2_qp(
ps_rc_lap_out->i4_L0_qp, ps_rc_ctxt->ps_rc_quant_ctxt);
WORD32 ai4_header_bits[2];
ps_rc_lap_out->i4_is_steady_state = 0;
if(ps_rc_lap_out->i4_L0_qp > 44)
ps_rc_lap_out->i4_L0_qp = 44;
if(ps_rc_lap_out->i4_L0_qp < 7 - ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset)
ps_rc_lap_out->i4_L0_qp = 7 - ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset;
ps_rc_lap_out->i4_L0_qp = ps_rc_lap_out->i4_L0_qp - 9;
ps_rc_lap_out->i4_is_model_valid = 0;
ps_rc_ctxt->s_rc_high_lvl_stat.i4_is_offline_model_used = 1;
ps_rc_ctxt->s_rc_high_lvl_stat.i8_bits_from_finalQP = -1;
ps_rc_ctxt->i4_normal_inter_pic = (i4_is_no_model_scd == 1);
while(1)
{
WORD32 i4_frame_qs_q3;
WORD32 i4_estimate_to_calc_frm_error_temp;
i_to_avg_bit_ratio = ihevce_get_i_to_avg_ratio(
(void *)ps_rc_ctxt,
ps_rc_lap_out,
1,
0,
1,
ps_rc_lap_out->ai4_offsets,
i4_update_delay);
ps_rc_ctxt->ai_to_avg_bit_ratio[i4_enc_frm_id] = i_to_avg_bit_ratio;
/** Use estimate of header bits from pre-enc*/
if(1 == i4_is_no_model_scd)
{
ps_rc_ctxt->i8_est_I_pic_header_bits =
get_est_hdr_bits(ps_rc_ctxt->rc_hdl, rc_pic_type);
}
else
{
WORD32 i4_curr_qscale = ihevce_rc_get_scaled_mpeg2_qp(
ps_rc_lap_out->i4_L0_qp, ps_rc_ctxt->ps_rc_quant_ctxt);
/*Assume that 30% of header bits are constant and remaining are dependent on Qp
and map them accordingly*/
ps_rc_ctxt->i8_est_I_pic_header_bits = (LWORD64)(
(.3 * ps_rc_lap_out->i8_est_I_pic_header_bits +
(1. - .3) * ps_rc_lap_out->i8_est_I_pic_header_bits * i4_ref_qscale) /
i4_curr_qscale);
}
/*get qp for scene cut frame based on offline data*/
index = ihevce_get_offline_index(
ps_rc_ctxt, ps_rc_lap_out->i4_num_pels_in_frame_considered);
/*Sub pic rC bits extraction */
i4_frame_qs_q3 = rc_get_qp_for_scd_frame(
ps_rc_ctxt->rc_hdl,
I_PIC,
ps_rc_lap_out->i8_frame_satd_act_accum,
ps_rc_lap_out->i4_num_pels_in_frame_considered,
(WORD32)ps_rc_ctxt->i8_est_I_pic_header_bits,
ps_rc_ctxt->ai4_lap_f_sim[i4_enc_frm_id],
(void *)&g_offline_i_model_coeff[index][0],
i_to_avg_bit_ratio,
1,
ps_rc_ctxt->af_sum_weigh[i4_enc_frm_id],
ps_rc_lap_out->ps_frame_info,
ps_rc_ctxt->i4_rc_pass,
(rc_pic_type != I_PIC),
((ps_rc_lap_out->i4_rc_temporal_lyr_id != ps_rc_ctxt->i4_max_temporal_lyr) ||
(!ps_rc_ctxt->i4_max_temporal_lyr)),
1,
&i4_total_bits,
&i4_current_bits_estimated,
ps_rc_lap_out->i4_use_offline_model_2pass,
ai8_i_tex_bits,
af_i_qs,
i4_best_br_id,
&i4_estimate_to_calc_frm_error_temp);
i4_hevc_frame_qp = ihevce_rc_get_scaled_hevc_qp_from_qs_q3(
i4_frame_qs_q3, ps_rc_ctxt->ps_rc_quant_ctxt);
/*Get corresponding q scale*/
i4_frame_qp =
ihevce_rc_get_scaled_mpeg2_qp(i4_hevc_frame_qp, ps_rc_ctxt->ps_rc_quant_ctxt);
if(i4_hevc_frame_qp > ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qp)
i4_hevc_frame_qp = ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qp;
{
WORD32 i4_init_qscale = ihevce_rc_get_scaled_mpeg2_qp(
ps_rc_lap_out->i4_L0_qp, ps_rc_ctxt->ps_rc_quant_ctxt);
f_percent_error = (float)(abs(i4_init_qscale - i4_frame_qp)) / i4_init_qscale;
if(f_percent_error < f_min_error)
{
f_min_error = f_percent_error;
i4_min_error_hevc_qp = i4_hevc_frame_qp;
i4_i_to_rest_ratio_final = i_to_avg_bit_ratio;
/*Get the bits estimated for least error*/
*pi4_tot_bits_estimated = i4_current_bits_estimated;
i4_estimate_to_calc_frm_error = i4_estimate_to_calc_frm_error_temp;
}
else
{}
ASSERT(*pi4_tot_bits_estimated != 0);
}
i4_count++;
if(/*(ps_rc_lap_out->i4_L0_qp == i4_hevc_frame_qp) ||*/ (i4_count > 17))
break;
ps_rc_lap_out->i4_L0_qp++;
}
ps_rc_lap_out->i4_L0_qp = i4_min_error_hevc_qp;
i4_hevc_frame_qp = i4_min_error_hevc_qp;
if(2 == i4_is_no_model_scd)
{
/* SGI & Enc Loop Parallelism related changes*/
/*model reset not required if it is first frame*/
if(ps_rc_ctxt->i4_is_first_frame_encoded && !i4_fade_scene &&
!ps_rc_ctxt->ai4_I_model_only_reset[i4_enc_frm_id] &&
!ps_rc_ctxt->ai4_is_non_I_scd_pic[i4_enc_frm_id] &&
!ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id] &&
!ps_rc_ctxt->ai4_is_cmplx_change_reset_model[i4_enc_frm_id])
{
ps_rc_ctxt->ai4_is_frame_scd[i4_enc_frm_id] = 1;
/*reset all pic type is first frame encoded flag*/
ASSERT(pic_type == IV_IDR_FRAME || pic_type == IV_I_FRAME);
}
else if(ps_rc_ctxt->ai4_I_model_only_reset[i4_enc_frm_id])
{
rc_reset_first_frame_coded_flag(ps_rc_ctxt->rc_hdl, I_PIC);
ASSERT(rc_pic_type == I_PIC);
ASSERT(ps_rc_ctxt->ai4_is_non_I_scd_pic[i4_enc_frm_id] == 0);
}
else if(
ps_rc_ctxt->ai4_is_non_I_scd_pic[i4_enc_frm_id] ||
ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id] ||
ps_rc_ctxt->ai4_is_cmplx_change_reset_model[i4_enc_frm_id] || i4_fade_scene)
{
/*Only when there are back to back scene cuts we need a non- Ipic will be marked as scene cut*/
/* Same path can also be followed during pause to resume detection to determine cur frame qp however handling during update is different*/
WORD32 i4_prev_qp, i, i4_new_qp_hevc_qp, I_hevc_qp, cur_hevc_qp;
/*both cannot be set at same time since lap cannot mark same frame as both scene cut and pause to resume flag*/
ASSERT(
(ps_rc_ctxt->ai4_is_non_I_scd_pic[i4_enc_frm_id] &&
ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id]) == 0);
I_hevc_qp = i4_hevc_frame_qp;
/*alter ai4_prev_pic_hevc_qp so that qp restriction ll not let even other pictures temporary scd are thrashed*/
//if(ps_rc_lap_out->i4_rc_temporal_lyr_id != ps_rc_ctxt->i4_max_temporal_lyr)
{
if(ps_rc_ctxt->i4_field_pic == 0)
{
for(i = 1; i < ps_rc_ctxt->i4_num_active_pic_type; i++)
{
i4_prev_qp = ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][i];
i4_new_qp_hevc_qp = I_hevc_qp + i;
i4_new_qp_hevc_qp = ihevce_clip_min_max_qp(
ps_rc_ctxt, i4_new_qp_hevc_qp, (picture_type_e)i, i - 1);
if(i4_prev_qp < i4_new_qp_hevc_qp)
{
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][i] =
i4_new_qp_hevc_qp;
}
}
}
else
{ /*field case*/
for(i = 1; i < ps_rc_ctxt->i4_num_active_pic_type; i++)
{
i4_prev_qp = ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][i];
i4_new_qp_hevc_qp = I_hevc_qp + i;
i4_new_qp_hevc_qp = ihevce_clip_min_max_qp(
ps_rc_ctxt, i4_new_qp_hevc_qp, (picture_type_e)i, i - 1);
if(i4_prev_qp < i4_new_qp_hevc_qp)
{
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][i] =
i4_new_qp_hevc_qp;
}
i4_prev_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][i + FIELD_OFFSET];
i4_new_qp_hevc_qp = I_hevc_qp + i;
i4_new_qp_hevc_qp = ihevce_clip_min_max_qp(
ps_rc_ctxt, i4_new_qp_hevc_qp, (picture_type_e)i, i - 1);
if(i4_prev_qp < i4_new_qp_hevc_qp)
{
ps_rc_ctxt
->ai4_prev_pic_hevc_qp[i4_scene_num][i + FIELD_OFFSET] =
i4_new_qp_hevc_qp;
}
}
}
}
{
WORD32 i4_updated_qp = ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][i];
WORD32 i4_scale;
if(I_hevc_qp == i4_updated_qp)
i4_scale = 16;
else if(I_hevc_qp == (i4_updated_qp - 1))
i4_scale = 14;
else if(I_hevc_qp == (i4_updated_qp - 2))
i4_scale = 12;
else
i4_scale = 10;
*pi4_tot_bits_estimated = (i4_scale * (*pi4_tot_bits_estimated)) >> 4;
i4_estimate_to_calc_frm_error =
(i4_scale * i4_estimate_to_calc_frm_error) >> 4;
}
if(call_type == ENC_GET_QP)
{
ps_rc_lap_out->i8_est_text_bits = *pi4_tot_bits_estimated;
}
ASSERT(*pi4_tot_bits_estimated != 0);
/*use previous frame qp of same pic type or SCD i frame qp with offset whichever is maximum*/
/*For field case adding of grater than 4 results in the qp increasing greatly when compared to previous pics/fields*/
if(rc_pic_type <= FIELD_OFFSET)
cur_hevc_qp = I_hevc_qp + rc_pic_type;
else
cur_hevc_qp = I_hevc_qp + (rc_pic_type - FIELD_OFFSET);
i4_prev_qp = ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][rc_pic_type];
if((cur_hevc_qp < i4_prev_qp) && (ps_rc_ctxt->i4_num_active_pic_type > 2) &&
(is_first_frame_coded(ps_rc_ctxt->rc_hdl)) && (!i4_fade_scene))
{
cur_hevc_qp = i4_prev_qp;
}
i4_frame_qp =
ihevce_rc_get_scaled_mpeg2_qp(cur_hevc_qp, ps_rc_ctxt->ps_rc_quant_ctxt);
i4_hevc_frame_qp = cur_hevc_qp;
//ps_rc_ctxt->i4_is_non_I_scd_pic = 0;
rc_reset_first_frame_coded_flag(ps_rc_ctxt->rc_hdl, rc_pic_type);
}
else
{}
}
if((1 == i4_is_no_model_scd) && (call_type == ENC_GET_QP))
{
WORD32 i4_clip_QP;
i4_frame_qp_q6 =
clip_qp_based_on_prev_ref(ps_rc_ctxt->rc_hdl, rc_pic_type, 1, i4_scene_num);
i4_clip_QP =
ihevce_rc_get_scaled_hevce_qp_q6(i4_frame_qp_q6, ps_rc_ctxt->u1_bit_depth);
if(ps_rc_ctxt->i4_rc_pass != 2)
{
i4_hevc_frame_qp = i4_clip_QP;
}
if((rc_pic_type == P_PIC) || (rc_pic_type == P1_PIC))
{
*pi4_tot_bits_estimated = (*pi4_tot_bits_estimated * 11) >> 4; /* P picture*/
i4_estimate_to_calc_frm_error = (i4_estimate_to_calc_frm_error * 11) >> 4;
}
else if((rc_pic_type == B_PIC) || (rc_pic_type == BB_PIC))
{
*pi4_tot_bits_estimated = (*pi4_tot_bits_estimated * 9) >> 4; /* B layer 1*/
i4_estimate_to_calc_frm_error = (i4_estimate_to_calc_frm_error * 9) >> 4;
}
else if((rc_pic_type == B1_PIC) || (rc_pic_type == B11_PIC))
{
*pi4_tot_bits_estimated = (*pi4_tot_bits_estimated * 7) >> 4; /* B layer 2*/
i4_estimate_to_calc_frm_error = (i4_estimate_to_calc_frm_error * 7) >> 4;
}
else if((rc_pic_type == B2_PIC) || (rc_pic_type == B22_PIC))
{
*pi4_tot_bits_estimated = (*pi4_tot_bits_estimated * 5) >> 4; /* B layer 3*/
i4_estimate_to_calc_frm_error = (i4_estimate_to_calc_frm_error * 5) >> 4;
}
}
rc_add_est_tot(ps_rc_ctxt->rc_hdl, *pi4_tot_bits_estimated);
}
ASSERT(i4_hevc_frame_qp >= -ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset);
/*constraint qp swing based on neighbour frames*/
if(is_first_frame_coded(ps_rc_ctxt->rc_hdl))
{
if(ps_rc_ctxt->i4_field_pic == 0)
{
/*In dissolve case the p frame comes before an I pic and ref b comes after then what
happens is b frame qp is restricted by the p frame qp so changed it to prev ref pic type*/
if(rc_pic_type != I_PIC && rc_pic_type != P_PIC)
{
if(ps_rc_lap_out->i4_rc_temporal_lyr_id == 1)
{
picture_type_e prev_ref_pic_type =
rc_getprev_ref_pic_type(ps_rc_ctxt->rc_hdl);
if(i4_hevc_frame_qp >
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][prev_ref_pic_type] + 3)
{
if(ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][prev_ref_pic_type] >
0)
i4_hevc_frame_qp =
ps_rc_ctxt
->ai4_prev_pic_hevc_qp[i4_scene_num][prev_ref_pic_type] +
3;
}
}
else if(
i4_hevc_frame_qp >
(ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][rc_pic_type - 1] + 3))
{
/*allow max of +3 compared to previous frame*/
if(ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][rc_pic_type - 1] > 0)
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][rc_pic_type - 1] + 3;
}
}
if((rc_pic_type != I_PIC && rc_pic_type != P_PIC) &&
(i4_hevc_frame_qp <
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][rc_pic_type - 1]))
{
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][rc_pic_type - 1];
}
/** Force non-ref B pic qp to be ref_B_PIC_qp - 1. This is not valid for when max teporla later is less than 2*/
if(temporal_layer_id == ps_rc_ctxt->i4_max_temporal_lyr &&
ps_rc_ctxt->i4_max_temporal_lyr > 1)
{
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][rc_pic_type - 1] + 1;
}
}
else /*for field case*/
{
if(ps_rc_lap_out->i4_rc_temporal_lyr_id >= 1)
{
/*To make the comparison of qp with the top field's of previous layer tempor layer id matches with the pic type. */
if(i4_hevc_frame_qp >
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num]
[ps_rc_lap_out->i4_rc_temporal_lyr_id] +
3)
{
/*allow max of +3 compared to previous frame*/
if(0 <
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num]
[ps_rc_lap_out->i4_rc_temporal_lyr_id])
i4_hevc_frame_qp =
ps_rc_ctxt
->ai4_prev_pic_hevc_qp[i4_scene_num]
[ps_rc_lap_out->i4_rc_temporal_lyr_id] +
3;
}
if(i4_hevc_frame_qp <
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num]
[ps_rc_lap_out->i4_rc_temporal_lyr_id])
{
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num]
[ps_rc_lap_out->i4_rc_temporal_lyr_id];
}
/** Force non-ref B pic qp to be ref_B_PIC_qp - 1. This is not valid for when max teporla later is less than 2*/
if(temporal_layer_id == ps_rc_ctxt->i4_max_temporal_lyr &&
ps_rc_ctxt->i4_max_temporal_lyr > 1)
{
i4_hevc_frame_qp =
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num]
[ps_rc_lap_out->i4_rc_temporal_lyr_id] +
1;
}
}
/** At lower range qp swing for same pic type is also imposed to make sure
qp does not fall from 10 to 4 since they differ by only one q scale*/
}
}
/**clip to min qp which is user configurable*/
i4_hevc_frame_qp = ihevce_clip_min_max_qp(
ps_rc_ctxt, i4_hevc_frame_qp, rc_pic_type, ps_rc_lap_out->i4_rc_temporal_lyr_id);
#if 1 //FRAME_PARALLEL_LVL
ps_rc_ctxt->i4_est_text_bits_ctr_get_qp++; //ELP_RC
ps_rc_ctxt->i4_est_text_bits_ctr_get_qp =
(ps_rc_ctxt->i4_est_text_bits_ctr_get_qp % (ps_rc_ctxt->i4_num_frame_parallel));
#endif
/** the estimates are reset only duing enc call*/
#if USE_USER_FIRST_FRAME_QP
/*I_PIC check is necessary coz pre-enc can query for qp even before first frame update has happened*/
if(!ps_rc_ctxt->i4_is_first_frame_encoded && rc_pic_type == I_PIC)
{
i4_hevc_frame_qp = ps_rc_ctxt->i4_init_frame_qp_user;
DBG_PRINTF("FIXED START QP PATH *************************\n");
}
#endif
}
if(CONST_QP != e_rc_type)
{
ASSERT(*pi4_tot_bits_estimated != 0);
}
ps_rc_ctxt->s_rc_high_lvl_stat.i4_finalQP = i4_hevc_frame_qp;
if(ps_rc_lap_out->i4_is_model_valid)
{
get_bits_for_final_qp(
ps_rc_ctxt->rc_hdl,
&ps_rc_ctxt->s_rc_high_lvl_stat.i4_modelQP,
&ps_rc_ctxt->s_rc_high_lvl_stat.i4_maxEbfQP,
&ps_rc_ctxt->s_rc_high_lvl_stat.i8_bits_from_finalQP,
i4_hevc_frame_qp,
ihevce_rc_get_scaled_mpeg2_qp_q6(
i4_hevc_frame_qp + ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset,
ps_rc_ctxt->u1_bit_depth),
i4_cur_est_header_bits,
i4_est_tex_bits,
i4_vbv_buf_max_bits,
rc_pic_type,
ps_rc_lap_out->i4_rc_display_num);
}
i4_deltaQP = ihevce_ebf_based_rc_correction_to_avoid_overflow(
ps_rc_ctxt, ps_rc_lap_out, pi4_tot_bits_estimated);
i4_hevc_frame_qp += i4_deltaQP;
/**clip to min qp which is user configurable*/
i4_hevc_frame_qp = ihevce_clip_min_max_qp(
ps_rc_ctxt, i4_hevc_frame_qp, rc_pic_type, ps_rc_lap_out->i4_rc_temporal_lyr_id);
/*set estimate status for frame level error calculation*/
if(i4_estimate_to_calc_frm_error > 0)
{
rc_set_estimate_status(
ps_rc_ctxt->rc_hdl,
i4_estimate_to_calc_frm_error - ps_rc_ctxt->i8_est_I_pic_header_bits,
ps_rc_ctxt->i8_est_I_pic_header_bits,
ps_rc_ctxt->i4_est_text_bits_ctr_get_qp);
}
else
{
rc_set_estimate_status(
ps_rc_ctxt->rc_hdl,
-1,
ps_rc_ctxt->i8_est_I_pic_header_bits,
ps_rc_ctxt->i4_est_text_bits_ctr_get_qp);
}
ps_rc_lap_out->i8_est_text_bits = *pi4_tot_bits_estimated;
/*B pictures which are in fades will take the highest QP of either side of P pics*/
if(ps_rc_lap_out->i4_rc_pic_type == IV_B_FRAME &&
(ps_rc_lap_out->i4_rc_scene_type == SCENE_TYPE_FADE_IN ||
ps_rc_lap_out->i4_rc_scene_type == SCENE_TYPE_FADE_OUT))
{
i4_hevc_frame_qp =
MAX(ps_rc_ctxt->ai4_last_tw0_lyr0_pic_qp[0], ps_rc_ctxt->ai4_last_tw0_lyr0_pic_qp[1]);
}
/*saving the last two pics of layer 0*/
if(0 == ps_rc_lap_out->i4_rc_temporal_lyr_id)
{
ps_rc_ctxt->ai4_last_tw0_lyr0_pic_qp[1] = ps_rc_ctxt->ai4_last_tw0_lyr0_pic_qp[0];
ps_rc_ctxt->ai4_last_tw0_lyr0_pic_qp[0] = i4_hevc_frame_qp;
}
return i4_hevc_frame_qp;
}
/*##########################################################*/
/******* END OF ENC THRD QP QUERY FUNCTIONS ****************/
/*########################################################*/
/*####################################################*/
/******* START OF I2AVG RATIO FUNCTIONS **************/
/*##################################################*/
/**
******************************************************************************
*
* @brief function to get i_to_avg_rest at scene cut frame based on data available from LAP
*
* @par Description
*
* @param[in] pv_rc_ctxt
* void pointer to rc ctxt
* @param[in] ps_rc_lap_out : pointer to lap out structure
* @param[in] i4_update_delay : The Delay in the update. This can happen for dist. case!
* All decision should consider this delay for updation!
* @return WORD32 i_to_rest bit ratio
*
******************************************************************************
*/
float ihevce_get_i_to_avg_ratio(
void *pv_rc_ctxt,
rc_lap_out_params_t *ps_rc_lap_out,
WORD32 i_to_p_qp_offset,
WORD32 i4_offset_flag,
WORD32 i4_call_type,
WORD32 ai4_qp_offsets[4],
WORD32 i4_update_delay)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
WORD32 i = 0, k = 0, num_frames_in_lap[MAX_PIC_TYPE] = { 0 }, ai4_pic_dist[MAX_PIC_TYPE],
ai4_pic_dist_in_cur_gop[MAX_PIC_TYPE] = { 0 };
WORD32 i4_num_b, i4_num_frms_traversed_in_lap = 0, total_frms_considered = 0,
i4_flag_i_frame_exit = 0, u4_rc_scene_number;
rc_lap_out_params_t *ps_cur_rc_lap_out = ps_rc_lap_out;
rc_lap_out_params_t *ps_cur_rc_lap_out_I = ps_rc_lap_out;
double complexity[MAX_PIC_TYPE] = { 0 }, d_first_i_complexity = 0, d_first_p_complexity = 0.0f,
cur_lambda_modifer, den = 0, average_intra_complexity = 0;
double i_frm_lambda_modifier;
float i_to_rest_bit_ratio = 8.00;
picture_type_e curr_rc_pic_type;
LWORD64 i8_l1_analysis_lap_comp = 0;
WORD32 i4_intra_frame_interval = rc_get_intra_frame_interval(ps_rc_ctxt->rc_hdl);
UWORD32 u4_L1_based_lap_complexity_q7 = 0;
WORD32 i4_frame_qp = 0, i4_I_frame_qp = 0;
WORD32 ai4_lambda_offsets[5] = { -3, -2, 2, 6, 7 };
/* The window for which your update is guaranteed */
WORD32 updated_window = ps_rc_ctxt->i4_num_frame_in_lap_window - i4_update_delay;
ASSERT(ps_rc_ctxt->i4_rc_pass != 2);
rc_get_pic_distribution(ps_rc_ctxt->rc_hdl, &ai4_pic_dist[0]);
if(ps_rc_ctxt->i4_max_temporal_lyr)
{
i4_num_b = ((WORD32)pow((float)2, ps_rc_ctxt->i4_max_temporal_lyr)) - 1;
}
else
{
i4_num_b = 0;
}
i_frm_lambda_modifier = ihevce_get_frame_lambda_modifier((WORD8)I_PIC, 0, 1, 1, i4_num_b);
/* check should be wrt inter frame interval*/
/*If lap frames are not sufficient return default ratio*/
u4_rc_scene_number = ps_cur_rc_lap_out_I->u4_rc_scene_num;
if(updated_window < 4)
{
return i_to_rest_bit_ratio;
}
k = 0;
if(ps_cur_rc_lap_out != NULL)
{
WORD32 i4_temp_frame_qp;
if(ps_cur_rc_lap_out->i4_L0_qp == -1)
{
i4_frame_qp = ps_cur_rc_lap_out->i4_L1_qp;
i4_I_frame_qp = ps_cur_rc_lap_out->i4_L1_qp - 3;
}
else
{
i4_frame_qp = ps_cur_rc_lap_out->i4_L0_qp;
i4_I_frame_qp = ps_cur_rc_lap_out->i4_L0_qp - 3;
}
do
{
curr_rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_cur_rc_lap_out->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_cur_rc_lap_out->i4_rc_temporal_lyr_id,
ps_cur_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
cur_lambda_modifer = ihevce_get_frame_lambda_modifier(
(WORD8)curr_rc_pic_type,
ps_cur_rc_lap_out->i4_rc_temporal_lyr_id,
1,
ps_cur_rc_lap_out->i4_rc_is_ref_pic,
i4_num_b);
if(curr_rc_pic_type == I_PIC)
{
i4_temp_frame_qp = i4_frame_qp + ai4_lambda_offsets[curr_rc_pic_type];
}
else
{
i4_temp_frame_qp =
i4_frame_qp + ai4_lambda_offsets[ps_cur_rc_lap_out->i4_rc_temporal_lyr_id + 1];
i4_temp_frame_qp =
i4_temp_frame_qp +
ps_cur_rc_lap_out->ai4_offsets[ps_cur_rc_lap_out->i4_rc_temporal_lyr_id + 1];
}
i4_temp_frame_qp = CLIP3(i4_temp_frame_qp, 1, 51);
i4_I_frame_qp = CLIP3(i4_I_frame_qp, 1, 51);
if(curr_rc_pic_type == I_PIC)
{
complexity[I_PIC] += (double)ps_cur_rc_lap_out->ai8_pre_intra_sad[i4_I_frame_qp];
if(total_frms_considered == 0)
d_first_i_complexity =
(double)ps_cur_rc_lap_out->ai8_pre_intra_sad[i4_I_frame_qp];
num_frames_in_lap[I_PIC]++;
i8_l1_analysis_lap_comp +=
(LWORD64)(1.17 * ps_cur_rc_lap_out->i8_raw_pre_intra_sad);
}
else
{
if((num_frames_in_lap[P_PIC] == 0) && (curr_rc_pic_type == P_PIC))
d_first_p_complexity =
(double)ps_cur_rc_lap_out->ai8_pre_intra_sad[i4_I_frame_qp];
if(total_frms_considered == 0)
{
num_frames_in_lap[I_PIC]++;
{
complexity[I_PIC] +=
(double)ps_cur_rc_lap_out->ai8_pre_intra_sad[i4_I_frame_qp];
d_first_i_complexity =
(double)ps_cur_rc_lap_out->ai8_pre_intra_sad[i4_I_frame_qp];
}
}
else
{
/*SAD is scaled according the lambda parametrs use to make it proportional to bits consumed in the end*/
#if !USE_SQRT
//complexity[curr_rc_pic_type] += (double)(MIN(ps_cur_rc_lap_out->ai8_frame_acc_coarse_me_sad[i4_temp_frame_qp],ps_cur_rc_lap_out->i8_pre_intra_sad)/(/*(cur_lambda_modifer/i_frm_lambda_modifier) * */pow(1.125,(ps_rc_lap_out->i4_rc_temporal_lyr_id + 1/*i_to_p_qp_offset*/))));
if((curr_rc_pic_type > P_PIC) &&
(ps_rc_lap_out->i4_rc_quality_preset == IHEVCE_QUALITY_P6))
complexity[curr_rc_pic_type] +=
(double)(ps_cur_rc_lap_out->ai8_frame_acc_coarse_me_sad
[i4_temp_frame_qp]); // /(/*(cur_lambda_modifer/i_frm_lambda_modifier) * */pow(1.125,(ps_rc_lap_out->i4_rc_temporal_lyr_id + 1/*i_to_p_qp_offset*/))));
else
complexity[curr_rc_pic_type] += (double)(MIN(
ps_cur_rc_lap_out->ai8_frame_acc_coarse_me_sad[i4_temp_frame_qp],
ps_cur_rc_lap_out->ai8_pre_intra_sad
[i4_temp_frame_qp])); ///(/*(cur_lambda_modifer/i_frm_lambda_modifier) * */pow(1.125,(ps_rc_lap_out->i4_rc_temporal_lyr_id + 1/*i_to_p_qp_offset*/))));
#else
complexity[curr_rc_pic_type] +=
MIN(ps_cur_rc_lap_out->ai8_frame_acc_coarse_me_sad[i4_temp_frame_qp],
ps_cur_rc_lap_out->i8_pre_intra_sad) /
(sqrt(cur_lambda_modifer / i_frm_lambda_modifier) *
pow(1.125, (ps_rc_lap_out->i4_rc_temporal_lyr_id + 1)));
#endif
num_frames_in_lap[curr_rc_pic_type]++;
}
i8_l1_analysis_lap_comp += (LWORD64)(
(float)ps_cur_rc_lap_out->i8_raw_l1_coarse_me_sad /
pow(1.125, curr_rc_pic_type));
}
if(ps_rc_lap_out->i4_rc_quality_preset == IHEVCE_QUALITY_P6)
{
if(curr_rc_pic_type < B_PIC)
{
/*accumulate average intra sad*/
average_intra_complexity +=
ps_cur_rc_lap_out
->ai8_pre_intra_sad[i4_I_frame_qp] /*/i_frm_lambda_modifier*/;
i4_num_frms_traversed_in_lap++;
}
}
else
{
/*accumulate average intra sad*/
average_intra_complexity +=
ps_cur_rc_lap_out->ai8_pre_intra_sad[i4_I_frame_qp] /*/i_frm_lambda_modifier*/;
i4_num_frms_traversed_in_lap++;
}
ai4_pic_dist_in_cur_gop[curr_rc_pic_type]++;
i++;
total_frms_considered++;
i4_num_frms_traversed_in_lap++;
ps_cur_rc_lap_out = (rc_lap_out_params_t *)ps_cur_rc_lap_out->ps_rc_lap_out_next_encode;
if((ps_cur_rc_lap_out == NULL) ||
((total_frms_considered + k) == i4_intra_frame_interval) || (i >= updated_window))
{
break;
}
if((i >= (ps_rc_ctxt->i4_next_sc_i_in_rc_look_ahead - k) ||
(ps_cur_rc_lap_out->i4_rc_pic_type == IV_I_FRAME) ||
(ps_cur_rc_lap_out->i4_rc_pic_type == IV_IDR_FRAME)) &&
(i4_offset_flag == 1))
{
break;
}
/*If an I frame enters the lookahead it can cause bit allocation to go bad
if corresponding p/b frames are absent*/
if(((total_frms_considered + k) > (WORD32)(0.75f * i4_intra_frame_interval)) &&
((ps_cur_rc_lap_out->i4_rc_pic_type == IV_I_FRAME) ||
(ps_cur_rc_lap_out->i4_rc_pic_type == IV_IDR_FRAME)))
{
i4_flag_i_frame_exit = 1;
break;
}
} while(1);
if(total_frms_considered > 0)
{
float lap_L1_comp =
(float)i8_l1_analysis_lap_comp /
(total_frms_considered * ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width);
lap_L1_comp = rc_get_offline_normalized_complexity(
ps_rc_ctxt->u4_intra_frame_interval,
ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width,
lap_L1_comp,
ps_rc_ctxt->i4_rc_pass);
u4_L1_based_lap_complexity_q7 = (WORD32)((lap_L1_comp * (1 << 7)) + .05f);
}
else
{
u4_L1_based_lap_complexity_q7 = 25;
}
if(i4_call_type == 1)
{
if(num_frames_in_lap[0] > 0)
{
float f_curr_i_to_sum = (float)(d_first_i_complexity / complexity[0]);
f_curr_i_to_sum = CLIP3(f_curr_i_to_sum, 0.1f, 100.0f);
rc_set_i_to_sum_api_ba(ps_rc_ctxt->rc_hdl, f_curr_i_to_sum);
}
}
for(i = 0; i < MAX_PIC_TYPE; i++)
{
if(num_frames_in_lap[i] > 0)
{
complexity[i] = complexity[i] / num_frames_in_lap[i];
}
}
/*for non - I scd case it is possible that entire LAP window might not have intra picture. Consider average intra sad when
atleast one I pic is not available*/
if(num_frames_in_lap[I_PIC] == 0)
{
ASSERT(i4_num_frms_traversed_in_lap);
complexity[I_PIC] = average_intra_complexity / i4_num_frms_traversed_in_lap;
}
/*get picture type distribution in LAP*/
if(num_frames_in_lap[I_PIC] == 0)
{
rc_get_pic_distribution(ps_rc_ctxt->rc_hdl, &ai4_pic_dist[0]);
}
else
{
memmove(ai4_pic_dist, num_frames_in_lap, sizeof(WORD32) * MAX_PIC_TYPE);
}
{
WORD32 num_inter_pic = 0;
for(i = 1; i < MAX_PIC_TYPE; i++)
{
den += complexity[i] * ai4_pic_dist[i];
}
for(i = 1; i < MAX_PIC_TYPE; i++)
{
num_inter_pic += ai4_pic_dist[i];
}
if(num_inter_pic > 0)
den = den / num_inter_pic;
else
den = 0.0;
}
if(den > 0)
i_to_rest_bit_ratio = (float)((complexity[I_PIC]) / den);
else
i_to_rest_bit_ratio = 15;
if((total_frms_considered < (WORD32)(0.75f * i4_intra_frame_interval)) &&
(total_frms_considered < (updated_window - 1)) &&
((UWORD32)total_frms_considered < ((ps_rc_ctxt->u4_max_frame_rate / 1000))))
{
/*This GOP will only sustain for few frames hence have strict restriction for I to rest ratio*/
if(i_to_rest_bit_ratio > 12)
i_to_rest_bit_ratio = 12;
if(i_to_rest_bit_ratio > 8 &&
total_frms_considered < (ps_rc_ctxt->i4_max_inter_frm_int * 2))
i_to_rest_bit_ratio = 8;
}
}
if((i4_call_type == 1) && (i_to_rest_bit_ratio < I_TO_REST_VVFAST) && (i4_offset_flag == 1))
{
float f_p_to_i_ratio = (float)(d_first_p_complexity / d_first_i_complexity);
if(ps_rc_lap_out->i8_frame_satd_act_accum <
(ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width * 1.5f))
rc_set_p_to_i_complexity_ratio(ps_rc_ctxt->rc_hdl, f_p_to_i_ratio);
}
/*Reset the pic distribution if I frame exit was encountered*/
if(ps_rc_ctxt->e_rate_control_type != CONST_QP)
{
rc_get_pic_distribution(ps_rc_ctxt->rc_hdl, &ai4_pic_dist[0]);
if((ai4_pic_dist_in_cur_gop[I_PIC] > 1) && (ai4_pic_dist[0] == 1))
{
i4_flag_i_frame_exit = 1;
}
if(i4_flag_i_frame_exit && (i4_call_type == 1))
{
if(ai4_pic_dist_in_cur_gop[I_PIC] == 0)
memmove(ai4_pic_dist_in_cur_gop, num_frames_in_lap, sizeof(WORD32) * MAX_PIC_TYPE);
rc_update_pic_distn_lap_to_rc(ps_rc_ctxt->rc_hdl, ai4_pic_dist_in_cur_gop);
rc_set_bits_based_on_complexity(
ps_rc_ctxt->rc_hdl, u4_L1_based_lap_complexity_q7, total_frms_considered);
}
}
return i_to_rest_bit_ratio;
}
/*##################################################*/
/******* END OF I2AVG RATIO FUNCTIONS **************/
/*################################################*/
/*#########################################################*/
/******* START OF QSCALE CONVERSION FUNCTIONS *************/
/*########################################################*/
/**
******************************************************************************
*
* @brief function to convert from qscale to qp
*
* @par Description
* @param[in] i4_frame_qs_q3 : QP value in qscale
* return frame qp
******************************************************************************
*/
WORD32 ihevce_rc_get_scaled_hevc_qp_from_qs_q3(WORD32 i4_frame_qs_q3, rc_quant_t *ps_rc_quant_ctxt)
{
if(i4_frame_qs_q3 > ps_rc_quant_ctxt->i2_max_qscale)
{
i4_frame_qs_q3 = ps_rc_quant_ctxt->i2_max_qscale;
}
else if(i4_frame_qs_q3 < ps_rc_quant_ctxt->i2_min_qscale)
{
i4_frame_qs_q3 = ps_rc_quant_ctxt->i2_min_qscale;
}
return (ps_rc_quant_ctxt->pi4_qscale_to_qp[i4_frame_qs_q3]);
}
/**
******************************************************************************
*
* @brief function to convert from qp to qscale
*
* @par Description
* @param[in] i4_frame_qp : QP value
* return value in qscale
******************************************************************************
*/
WORD32 ihevce_rc_get_scaled_mpeg2_qp(WORD32 i4_frame_qp, rc_quant_t *ps_rc_quant_ctxt)
{
//i4_frame_qp = i4_frame_qp >> 3; // Q3 format is mantained for accuarate calc at lower qp
WORD32 i4_qscale;
if(i4_frame_qp > ps_rc_quant_ctxt->i2_max_qp)
{
i4_frame_qp = ps_rc_quant_ctxt->i2_max_qp;
}
else if(i4_frame_qp < ps_rc_quant_ctxt->i2_min_qp)
{
i4_frame_qp = ps_rc_quant_ctxt->i2_min_qp;
}
i4_qscale = (ps_rc_quant_ctxt->pi4_qp_to_qscale[i4_frame_qp + ps_rc_quant_ctxt->i1_qp_offset] +
(1 << (QSCALE_Q_FAC_3 - 1))) >>
QSCALE_Q_FAC_3;
return i4_qscale;
}
/**
******************************************************************************
*
* @brief function to convert from qp to qscale
*
* @par Description : This function maps logarithmic QP values to linear QP
* values. The linear values are represented in Q6 format.
*
* @param[in] i4_frame_qp : QP value (log scale)
*
* @return value in QP (linear scale)
*
******************************************************************************
*/
WORD32 ihevce_rc_get_scaled_mpeg2_qp_q6(WORD32 i4_frame_qp, UWORD8 u1_bit_depth)
{
WORD32 i4_frame_qp_q6;
number_t s_frame_qp;
float f_qp;
(void)u1_bit_depth;
ASSERT(i4_frame_qp >= 0);
ASSERT(i4_frame_qp <= 51 + ((u1_bit_depth - 8) * 6));
f_qp = (float)pow((float)2, ((float)(i4_frame_qp - 4) / 6));
convert_float_to_fix(f_qp, &s_frame_qp);
convert_varq_to_fixq(s_frame_qp, &i4_frame_qp_q6, QSCALE_Q_FAC);
if(i4_frame_qp_q6 < (1 << QSCALE_Q_FAC))
i4_frame_qp_q6 = 1 << QSCALE_Q_FAC;
return i4_frame_qp_q6;
}
/**
******************************************************************************
*
* @brief function to convert from qscale to qp
*
* @par Description
* @param[in] i4_frame_qp_q6 : QP value in qscale. the input is assumed to be in q6 format
* return frame qp
******************************************************************************
*/
WORD32 ihevce_rc_get_scaled_hevce_qp_q6(WORD32 i4_frame_qp_q6, UWORD8 u1_bit_depth)
{
WORD32 i4_hevce_qp;
number_t s_hevce_qp, s_temp;
float f_mpeg2_qp, f_hevce_qp;
f_mpeg2_qp = (float)i4_frame_qp_q6 / (1 << QSCALE_Q_FAC);
f_hevce_qp = (6 * ((float)log(f_mpeg2_qp) / (float)log((float)2))) + 4;
convert_float_to_fix(f_hevce_qp, &s_hevce_qp);
/*rounf off to nearest integer*/
s_temp.sm = 1;
s_temp.e = 1;
add32_var_q(s_hevce_qp, s_temp, &s_hevce_qp);
number_t_to_word32(s_hevce_qp, &i4_hevce_qp);
if(i4_frame_qp_q6 == 0)
{
i4_hevce_qp = 0;
}
i4_hevce_qp -= ((u1_bit_depth - 8) * 6);
return i4_hevce_qp;
}
/**
******************************************************************************
*
* @brief function to convert from qp scale to qp
*
* @par Description : This function maps linear QP values to logarithimic QP
* values. The linear values are represented in Q3 format.
*
* @param[in] i4_frame_qp : QP value (linear scale, Q3 mode)
*
* @return value in QP (log scale)
*
******************************************************************************
*/
WORD32 ihevce_rc_get_scaled_hevce_qp_q3(WORD32 i4_frame_qp, UWORD8 u1_bit_depth)
{
WORD32 i4_hevce_qp;
number_t s_hevce_qp, s_temp;
if(i4_frame_qp == 0)
{
i4_hevce_qp = 0;
}
else
{
float f_mpeg2_qp, f_hevce_qp;
f_mpeg2_qp = (float)i4_frame_qp;
f_hevce_qp = (6 * ((float)log(f_mpeg2_qp) / (float)log((float)2) - 3)) + 4;
convert_float_to_fix(f_hevce_qp, &s_hevce_qp);
/*rounf off to nearest integer*/
s_temp.sm = 1;
s_temp.e = 1;
add32_var_q(s_hevce_qp, s_temp, &s_hevce_qp);
number_t_to_word32(s_hevce_qp, &i4_hevce_qp);
}
i4_hevce_qp -= ((u1_bit_depth - 8) * 6);
return i4_hevce_qp;
}
/*#######################################################*/
/******* END OF QSCALE CONVERSION FUNCTIONS *************/
/*######################################################*/
/*###############################################*/
/******* START OF SET,GET FUNCTIONS *************/
/*#############################################*/
/**
******************************************************************************
*
* @brief Convert pic type to rc pic type
*
* @par Description
*
*
* @param[in] pic_type
* Pic type
*
* @return rc_pic_type
*
******************************************************************************
*/
picture_type_e ihevce_rc_conv_pic_type(
IV_PICTURE_CODING_TYPE_T pic_type,
WORD32 i4_field_pic,
WORD32 i4_temporal_layer_id,
WORD32 i4_is_bottom_field,
WORD32 i4_top_field_first)
{
picture_type_e rc_pic_type = pic_type;
/*interlaced pictype are not supported*/
if(pic_type > 9 && i4_temporal_layer_id > 3) /**/
{
DBG_PRINTF("unsupported picture type or temporal id\n");
exit(0);
}
if(i4_field_pic == 0) /*Progressive Source*/
{
if(pic_type == IV_IDR_FRAME)
{
rc_pic_type = I_PIC;
}
else
{
rc_pic_type = (picture_type_e)pic_type;
/*return different picture type based on temporal layer*/
if(i4_temporal_layer_id > 1)
{
rc_pic_type = (picture_type_e)(pic_type + (i4_temporal_layer_id - 1));
}
}
}
else if(i4_field_pic == 1)
{
if(pic_type == IV_IDR_FRAME || pic_type == IV_I_FRAME)
{
rc_pic_type = I_PIC;
}
else if(i4_top_field_first == 1)
{
rc_pic_type = (picture_type_e)pic_type;
if(i4_temporal_layer_id <= 1)
{
if(i4_is_bottom_field == 1)
rc_pic_type = (picture_type_e)(pic_type + 4);
}
/*return different picture type based on temporal layer*/
if(i4_temporal_layer_id > 1)
{
if(i4_is_bottom_field == 0)
rc_pic_type = (picture_type_e)(pic_type + (i4_temporal_layer_id - 1));
else
rc_pic_type = (picture_type_e)(
pic_type + (i4_temporal_layer_id - 1) +
4); /*Offset of 4 for the bottomfield*/
}
}
else if(i4_top_field_first == 0)
{
rc_pic_type = (picture_type_e)pic_type;
if(i4_temporal_layer_id <= 1)
{
if(i4_is_bottom_field == 1)
rc_pic_type = (picture_type_e)(pic_type + 4);
}
/*return different picture type based on temporal layer*/
if(i4_temporal_layer_id > 1)
{
if(i4_is_bottom_field == 0)
rc_pic_type = (picture_type_e)(pic_type + (i4_temporal_layer_id - 1));
else
rc_pic_type = (picture_type_e)(
pic_type + (i4_temporal_layer_id - 1) + 4); /*Offset of 4 for the topfield*/
}
}
}
return rc_pic_type;
}
/**
******************************************************************************
*
* @brief function to update current frame intra cost
*
* @par Description
* @param[inout] ps_rc_ctxt
* @param[in] i8_cur_frm_intra_cost
******************************************************************************
*/
void ihevce_rc_update_cur_frm_intra_satd(
void *pv_ctxt, LWORD64 i8_cur_frm_intra_cost, WORD32 i4_enc_frm_id)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
ps_rc_ctxt->ai8_cur_frm_intra_cost[i4_enc_frm_id] = i8_cur_frm_intra_cost;
}
/**
******************************************************************************
*
* @brief function to return scene type
*
* @par Description
* @param[inout] ps_rc_lap_out
* @return i4_rc_scene_type
******************************************************************************
*/
/* Functions dependent on lap input*/
WORD32 ihevce_rc_lap_get_scene_type(rc_lap_out_params_t *ps_rc_lap_out)
{
return (WORD32)ps_rc_lap_out->i4_rc_scene_type;
}
/**
******************************************************************************
*
* @name ihevce_rc_get_pic_param
*
* @par Description
*
* @param[in] rc_pic_type
*
* @return void
*
******************************************************************************
*/
static void ihevce_rc_get_pic_param(
picture_type_e rc_pic_type, WORD32 *pi4_tem_lyr, WORD32 *pi4_is_bottom_field)
{
/*bottom field determination*/
if(rc_pic_type >= P1_PIC)
*pi4_is_bottom_field = 1;
else
*pi4_is_bottom_field = 0;
/*temporal lyr id determination*/
if(rc_pic_type == I_PIC || rc_pic_type == P_PIC || rc_pic_type == P1_PIC)
{
*pi4_tem_lyr = 0;
}
else if(rc_pic_type == B_PIC || rc_pic_type == BB_PIC)
{
*pi4_tem_lyr = 1;
}
else if(rc_pic_type == B1_PIC || rc_pic_type == B11_PIC)
{
*pi4_tem_lyr = 2;
}
else if(rc_pic_type == B2_PIC || rc_pic_type == B22_PIC)
{
*pi4_tem_lyr = 3;
}
else
{
ASSERT(0);
}
}
/**
******************************************************************************
*
* @name ihevce_get_offline_index
*
* @par Description
*
* @param[in] ps_rc_ctxt - pointer to rc context
*
* @return index
*
******************************************************************************
*/
static WORD32 ihevce_get_offline_index(rc_context_t *ps_rc_ctxt, WORD32 i4_num_pels_in_frame)
{
WORD32 i4_rc_quality_preset = ps_rc_ctxt->i4_quality_preset;
WORD32 base = 1;
if(i4_num_pels_in_frame > 5000000) /*ultra HD*/
{
base = 0;
}
else if(i4_num_pels_in_frame > 1500000) /*Full HD*/
{
base = 5;
}
else if(i4_num_pels_in_frame > 600000) /*720p*/
{
base = 10;
}
else /*SD*/
{
base = 15;
}
/*based on preset choose coeff*/
if(i4_rc_quality_preset == IHEVCE_QUALITY_P0) /*Pristine quality*/
{
return base;
}
else if(i4_rc_quality_preset == IHEVCE_QUALITY_P2) /*High quality*/
{
return base + 1;
}
else if(
(i4_rc_quality_preset == IHEVCE_QUALITY_P5) ||
(i4_rc_quality_preset == IHEVCE_QUALITY_P6)) /*Extreme speed */
{
return base + 4;
}
else if(i4_rc_quality_preset == IHEVCE_QUALITY_P4) /*High speed */
{
return base + 3;
}
else if(i4_rc_quality_preset == IHEVCE_QUALITY_P3) /*default assume Medium speed*/
{
return base + 2;
}
else
{
ASSERT(0);
}
return base + 2;
}
/**
******************************************************************************
*
* @name ihevce_get_frame_lambda_modifier
*
* @par Description
*
* @param[in] pic_type
* i4_rc_temporal_lyr_id
* @param[in] i4_first_field
* @param[in] i4_rc_is_ref_pic
* @return lambda_modifier
*
******************************************************************************
*/
static double ihevce_get_frame_lambda_modifier(
WORD8 pic_type,
WORD32 i4_rc_temporal_lyr_id,
WORD32 i4_first_field,
WORD32 i4_rc_is_ref_pic,
WORD32 i4_num_b_frms)
{
double lambda_modifier;
WORD32 num_b_frms = i4_num_b_frms, first_field = i4_first_field;
if(I_PIC == pic_type)
{
double temporal_correction_islice = 1.0 - 0.05 * num_b_frms;
temporal_correction_islice = MAX(0.5, temporal_correction_islice);
lambda_modifier = 0.57 * temporal_correction_islice;
}
else if(P_PIC == pic_type)
{
if(first_field)
lambda_modifier = 0.442; //0.442*0.8;
else
lambda_modifier = 0.442;
//lambda_modifier *= pow(2.00,(double)(1.00/3.00));
}
else
{
/* BSLICE */
if(1 == i4_rc_is_ref_pic)
{
lambda_modifier = 0.3536;
}
else if(2 == i4_rc_is_ref_pic)
{
lambda_modifier = 0.45;
}
else
{
lambda_modifier = 0.68;
}
/* TODO: Disable lambda modification for interlace encode to match HM runs */
//if(0 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic)
{
/* modify b lambda further based on temporal id */
if(i4_rc_temporal_lyr_id)
{
lambda_modifier *= 3.00;
}
}
//lambda_modifier *= pow(2.00,(double)((1.00/3.00) * (i4_rc_temporal_lyr_id + 1)));
}
/* modify the base lambda according to lambda modifier */
lambda_modifier = sqrt(lambda_modifier);
return lambda_modifier;
}
/*!
******************************************************************************
* \if Function name : get_avg_bitrate_bufsize
*
* \brief
*
* \param[in] *pv_ctxt -> rc context
*
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
void get_avg_bitrate_bufsize(void *pv_ctxt, LWORD64 *pi8_bitrate, LWORD64 *pi8_ebf)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
*pi8_bitrate = rc_get_bit_rate(ps_rc_ctxt->rc_hdl);
*pi8_ebf = rc_get_vbv_buf_size(ps_rc_ctxt->rc_hdl);
}
/**
******************************************************************************
*
* @name ihevce_get_dbf_buffer_size
*
* @par Description
*
* @param[in] ps_rc_ctxt - pointer to rc context
*
* @return qp
*
******************************************************************************
*/
void ihevce_get_dbf_buffer_size(
void *pv_rc_ctxt, UWORD32 *pi4_buffer_size, UWORD32 *pi4_dbf, UWORD32 *pi4_bit_rate)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
pi4_buffer_size[0] = (WORD32)ps_rc_ctxt->s_vbv_compliance.f_buffer_size;
pi4_dbf[0] = (WORD32)(ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level);
ASSERT(
ps_rc_ctxt->s_vbv_compliance.f_buffer_size >=
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level);
pi4_bit_rate[0] = (WORD32)ps_rc_ctxt->s_vbv_compliance.f_bit_rate;
}
/*!
******************************************************************************
* \if Function name : ihevce_set_L0_scd_qp
*
* \brief
*
* \param[in] *pv_ctxt -> rc context
*
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
void ihevce_set_L0_scd_qp(void *pv_rc_ctxt, WORD32 i4_scd_qp)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
ps_rc_ctxt->i4_L0_frame_qp = i4_scd_qp;
}
/**
******************************************************************************
*
* @name rc_get_buffer_level_unclip
*
* @par Description
*
* @param[in] pv_rc_ctxt
*
*
* @return void
*
******************************************************************************
*/
float rc_get_buffer_level_unclip(void *pv_rc_ctxt)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
return (ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level_unclip);
}
/**
******************************************************************************
*
* @brief Clip QP based on min and max frame qp
*
* @par Description
*
* @param[inout] ps_rc_ctxt
* pointer to rc context
*
* @param[in] rc_pic_type
* Pic type
*
* @return i4_hevc_frame_qp
*
******************************************************************************
*/
static WORD32 ihevce_clip_min_max_qp(
rc_context_t *ps_rc_ctxt,
WORD32 i4_hevc_frame_qp,
picture_type_e rc_pic_type,
WORD32 i4_rc_temporal_lyr_id)
{
ASSERT(i4_rc_temporal_lyr_id >= 0);
/**clip to min qp which is user configurable*/
if(rc_pic_type == I_PIC && i4_hevc_frame_qp < ps_rc_ctxt->i4_min_frame_qp)
{
i4_hevc_frame_qp = ps_rc_ctxt->i4_min_frame_qp;
}
else if(rc_pic_type == P_PIC && i4_hevc_frame_qp < (ps_rc_ctxt->i4_min_frame_qp + 1))
{
i4_hevc_frame_qp = ps_rc_ctxt->i4_min_frame_qp + 1;
}
else if(i4_hevc_frame_qp < (ps_rc_ctxt->i4_min_frame_qp + i4_rc_temporal_lyr_id + 1))
{
/** For B frame max qp is set based on temporal reference*/
i4_hevc_frame_qp = ps_rc_ctxt->i4_min_frame_qp + i4_rc_temporal_lyr_id + 1;
}
/* clip the Qp to MAX QP */
if(i4_hevc_frame_qp < ps_rc_ctxt->ps_rc_quant_ctxt->i2_min_qp)
{
i4_hevc_frame_qp = ps_rc_ctxt->ps_rc_quant_ctxt->i2_min_qp;
}
/**clip to max qp based on pic type*/
if(rc_pic_type == I_PIC && i4_hevc_frame_qp > ps_rc_ctxt->i4_max_frame_qp)
{
i4_hevc_frame_qp = ps_rc_ctxt->i4_max_frame_qp;
}
else if(rc_pic_type == P_PIC && i4_hevc_frame_qp > (ps_rc_ctxt->i4_max_frame_qp + 1))
{
i4_hevc_frame_qp = ps_rc_ctxt->i4_max_frame_qp + 1;
}
else if(i4_hevc_frame_qp > (ps_rc_ctxt->i4_max_frame_qp + i4_rc_temporal_lyr_id + 1))
{
/** For B frame max qp is set based on temporal reference*/
i4_hevc_frame_qp = ps_rc_ctxt->i4_max_frame_qp + i4_rc_temporal_lyr_id + 1;
}
/* clip the Qp to MAX QP */
if(i4_hevc_frame_qp > ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qp)
{
i4_hevc_frame_qp = ps_rc_ctxt->ps_rc_quant_ctxt->i2_max_qp;
}
return i4_hevc_frame_qp;
}
/*#############################################*/
/******* END OF SET,GET FUNCTIONS *************/
/*###########################################*/
/*#################################################*/
/******* START OF RC UPDATE FUNCTIONS **************/
/*#################################################*/
/**
******************************************************************************
*
* @brief updates the picture level information like bits consumed and
*
* @par Description
*
* @param[inout] ps_mem_tab
* pointer to memory descriptors table
*
* @param[in] ps_init_prms
* Create time static parameters
*
* @return void
*
******************************************************************************
*/
void ihevce_rc_update_pic_info(
void *pv_ctxt,
UWORD32 u4_total_bits_consumed,
UWORD32 u4_total_header_bits,
UWORD32 u4_frame_sad,
UWORD32 u4_frame_intra_sad,
IV_PICTURE_CODING_TYPE_T pic_type,
WORD32 i4_avg_frame_hevc_qp,
WORD32 i4_suppress_bpic_update,
WORD32 *pi4_qp_normalized_8x8_cu_sum,
WORD32 *pi4_8x8_cu_sum,
LWORD64 *pi8_sad_by_qscale,
ihevce_lap_output_params_t *ps_lap_out,
rc_lap_out_params_t *ps_rc_lap_out,
WORD32 i4_buf_id,
UWORD32 u4_open_loop_intra_sad,
LWORD64 i8_total_ssd_frame,
WORD32 i4_enc_frm_id)
{
LWORD64 a_mb_type_sad[2];
WORD32 a_mb_type_tex_bits[2];
/*dummy variables not used*/
WORD32 a_mb_in_type[2] = { 0, 0 };
LWORD64 a_mb_type_qp_q6[2] = { 0, 0 };
/*qp accumulation at */
WORD32 i4_avg_activity = 250; //hardcoding to usual value
WORD32 i4_intra_cost, i4_avg_frame_qp_q6, i;
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
WORD32 i4_frame_complexity, i4_bits_to_be_stuffed = 0, i4_is_last_frm_period = 0;
picture_type_e rc_pic_type = ihevce_rc_conv_pic_type(
pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
frame_info_t s_frame_info;
WORD32 i4_ctr = -1, i4_i, i4_j;
WORD32 i4_scene_num = ps_rc_lap_out->u4_rc_scene_num % MAX_SCENE_NUM;
/*update bit consumption. used only in rdopt*/
//ASSERT(ps_rc_ctxt->ai4_rdopt_bit_consumption_estimate[ps_rc_ctxt->i4_rdopt_bit_count] == -1);
//ASSERT(i4_buf_id>=0);
ps_rc_ctxt->ai4_rdopt_bit_consumption_estimate[ps_rc_ctxt->i4_rdopt_bit_count] =
u4_total_bits_consumed;
ps_rc_ctxt->ai4_rdopt_bit_consumption_buf_id[ps_rc_ctxt->i4_rdopt_bit_count] = i4_buf_id;
ps_rc_ctxt->i4_rdopt_bit_count =
(ps_rc_ctxt->i4_rdopt_bit_count + 1) % NUM_BUF_RDOPT_ENT_CORRECT;
{
LWORD64 i8_texture_bits = u4_total_bits_consumed - u4_total_header_bits;
ps_rc_lap_out->i4_use_offline_model_2pass = 0;
/*flag to guide whether 2nd pass can use offline model or not*/
if((abs(ps_rc_lap_out->i4_orig_rc_qp - i4_avg_frame_hevc_qp) < 2) &&
(i8_texture_bits <= (ps_rc_lap_out->i8_est_text_bits * 2.0f)) &&
(i8_texture_bits >= (ps_rc_lap_out->i8_est_text_bits * 0.5f)))
{
ps_rc_lap_out->i4_use_offline_model_2pass = 1;
}
}
/*Counter of number of bit alloction periods*/
if(rc_pic_type == I_PIC)
ps_rc_ctxt
->i8_num_bit_alloc_period++; //Currently only I frame periods are considerd as bit allocation period (Ignoring non- I scd and complexity reset flag
/*initialze frame info*/
init_frame_info(&s_frame_info);
s_frame_info.i4_rc_hevc_qp = i4_avg_frame_hevc_qp;
s_frame_info.i4_num_entries++;
s_frame_info.i8_L1_me_sad = ps_rc_lap_out->i8_raw_l1_coarse_me_sad;
s_frame_info.i8_L1_ipe_raw_sad = ps_rc_lap_out->i8_raw_pre_intra_sad;
s_frame_info.i4_num_entries++;
s_frame_info.i4_num_entries++;
s_frame_info.i8_L0_open_cost = (LWORD64)u4_open_loop_intra_sad;
s_frame_info.i4_num_entries++;
if(rc_pic_type == I_PIC)
s_frame_info.i8_L1_me_or_ipe_raw_sad = ps_rc_lap_out->i8_raw_pre_intra_sad;
else
s_frame_info.i8_L1_me_or_ipe_raw_sad = ps_rc_lap_out->i8_raw_l1_coarse_me_sad;
s_frame_info.i4_num_entries++;
s_frame_info.i4_poc = ps_rc_lap_out->i4_rc_poc;
s_frame_info.i4_num_entries++;
s_frame_info.i4_scene_type = ps_rc_lap_out->i4_rc_scene_type;
s_frame_info.i4_num_entries++;
s_frame_info.i4_non_i_scd = ps_rc_lap_out->i4_is_non_I_scd || ps_rc_lap_out->i4_is_I_only_scd;
s_frame_info.i4_num_entries++;
s_frame_info.i8_cl_sad = u4_frame_sad;
s_frame_info.i4_num_entries++;
s_frame_info.i8_header_bits = u4_total_header_bits;
s_frame_info.i4_num_entries++;
s_frame_info.i8_tex_bits = u4_total_bits_consumed - u4_total_header_bits;
s_frame_info.i4_num_entries++;
s_frame_info.e_pic_type = rc_pic_type;
s_frame_info.i4_num_entries++;
s_frame_info.i8_est_texture_bits = ps_rc_lap_out->i8_est_text_bits;
s_frame_info.i4_num_entries++;
s_frame_info.i4_lap_complexity_q7 = ps_rc_ctxt->ai4_lap_complexity_q7[i4_enc_frm_id];
s_frame_info.i4_num_entries++;
s_frame_info.i4_lap_f_sim = ps_rc_ctxt->ai4_lap_f_sim[i4_enc_frm_id];
s_frame_info.i4_num_entries++;
s_frame_info.i8_frame_acc_coarse_me_cost = ps_rc_lap_out->i8_frame_acc_coarse_me_cost;
s_frame_info.i4_num_entries++;
s_frame_info.i_to_avg_bit_ratio = ps_rc_ctxt->ai_to_avg_bit_ratio[i4_enc_frm_id];
s_frame_info.i4_num_entries++;
s_frame_info.i4_num_scd_in_lap_window = ps_rc_ctxt->ai4_num_scd_in_lap_window[i4_enc_frm_id];
s_frame_info.i4_num_entries++;
s_frame_info.i4_num_frames_b4_scd = ps_rc_ctxt->ai4_num_frames_b4_scd[i4_enc_frm_id];
s_frame_info.i4_num_entries++;
s_frame_info.i8_num_bit_alloc_period = ps_rc_ctxt->i8_num_bit_alloc_period;
s_frame_info.i4_num_entries++;
s_frame_info.i1_is_complexity_based_bits_reset =
(WORD8)ps_rc_lap_out->i4_is_cmplx_change_reset_bits;
s_frame_info.i4_num_entries++;
/*For the complexity based movement in 2nd pass*/
memmove(
(void *)s_frame_info.af_sum_weigh,
ps_rc_lap_out->ps_frame_info->af_sum_weigh,
sizeof(float) * MAX_PIC_TYPE * 3);
s_frame_info.i4_num_entries++;
/*store frame qp to clip qp accordingly*/
if(ps_rc_lap_out->i4_is_rc_model_needs_to_be_updated)
{
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][rc_pic_type] = i4_avg_frame_hevc_qp;
}
for(i4_i = 0; i4_i < MAX_NON_REF_B_PICS_IN_QUEUE_SGI; i4_i++)
{
if(ps_rc_lap_out->u4_rc_scene_num == ps_rc_ctxt->au4_prev_scene_num_multi_scene[i4_i])
{
i4_ctr = i4_i;
break;
}
}
if(-1 == i4_ctr)
{
ps_rc_ctxt->i4_prev_qp_ctr++;
ps_rc_ctxt->i4_prev_qp_ctr = ps_rc_ctxt->i4_prev_qp_ctr % MAX_NON_REF_B_PICS_IN_QUEUE_SGI;
i4_ctr = ps_rc_ctxt->i4_prev_qp_ctr;
ps_rc_ctxt->au4_prev_scene_num_multi_scene[i4_ctr] = ps_rc_lap_out->u4_rc_scene_num;
for(i4_j = 0; i4_j < MAX_PIC_TYPE; i4_j++)
{
ps_rc_ctxt->ai4_qp_for_previous_scene_multi_scene[i4_ctr][i4_j] = 0;
}
}
{
ps_rc_ctxt->ai4_qp_for_previous_scene_multi_scene[i4_ctr][rc_pic_type] =
i4_avg_frame_hevc_qp;
}
if(i4_scene_num < HALF_MAX_SCENE_ARRAY_QP)
{
WORD32 i4_i;
ps_rc_ctxt->ai4_scene_numbers[i4_scene_num + HALF_MAX_SCENE_ARRAY_QP] = 0;
for(i4_i = 0; i4_i < MAX_PIC_TYPE; i4_i++)
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num + HALF_MAX_SCENE_ARRAY_QP][i4_i] =
INIT_HEVCE_QP_RC;
}
else
{
WORD32 i4_i;
ps_rc_ctxt->ai4_scene_numbers[i4_scene_num - HALF_MAX_SCENE_ARRAY_QP] = 0;
for(i4_i = 0; i4_i < MAX_PIC_TYPE; i4_i++)
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num - HALF_MAX_SCENE_ARRAY_QP][i4_i] =
INIT_HEVCE_QP_RC;
}
/*update will have HEVC qp, convert it back to mpeg2 range qp for all internal calculations of RC*/
i4_avg_frame_qp_q6 = ps_rc_ctxt->ps_rc_quant_ctxt->pi4_qp_to_qscale_q_factor
[i4_avg_frame_hevc_qp + ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset];
if(pic_type == IV_I_FRAME || pic_type == IV_IDR_FRAME)
{
/*TODO : Take care of precision of a_mb_type_sad*/
a_mb_type_sad[0] =
(((pi8_sad_by_qscale[1] * i4_avg_frame_qp_q6) +
(((LWORD64)1) << (SAD_BY_QSCALE_Q + QSCALE_Q_FAC - 1))) >>
(SAD_BY_QSCALE_Q + QSCALE_Q_FAC)); //u4_frame_sad;
a_mb_type_sad[1] =
(((pi8_sad_by_qscale[0] * i4_avg_frame_qp_q6) +
(((LWORD64)1) << (SAD_BY_QSCALE_Q + QSCALE_Q_FAC - 1))) >>
(SAD_BY_QSCALE_Q + QSCALE_Q_FAC));
a_mb_type_tex_bits[0] =
u4_total_bits_consumed - u4_total_header_bits; //(u4_total_bits_consumed >> 3);
a_mb_type_tex_bits[1] = 0;
a_mb_in_type[0] = (ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width) >> 8;
a_mb_in_type[1] = 0;
}
else
{
/*TODO : Take care of precision of a_mb_type_sad*/
a_mb_type_sad[1] =
(((pi8_sad_by_qscale[0] * i4_avg_frame_qp_q6) +
(((LWORD64)1) << (SAD_BY_QSCALE_Q + QSCALE_Q_FAC - 1))) >>
(SAD_BY_QSCALE_Q + QSCALE_Q_FAC));
a_mb_type_tex_bits[0] =
u4_total_bits_consumed - u4_total_header_bits; //(u4_total_bits_consumed >> 3);
a_mb_type_sad[0] =
(((pi8_sad_by_qscale[1] * i4_avg_frame_qp_q6) +
(((LWORD64)1) << (SAD_BY_QSCALE_Q + QSCALE_Q_FAC - 1))) >>
(SAD_BY_QSCALE_Q + QSCALE_Q_FAC)); //u4_frame_sad;
a_mb_type_tex_bits[1] =
u4_total_bits_consumed - u4_total_header_bits; //(u4_total_bits_consumed >> 3);
a_mb_type_tex_bits[0] = 0;
a_mb_in_type[1] = (ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width) >> 8;
a_mb_in_type[0] = 0;
}
ASSERT(a_mb_type_sad[0] >= 0);
ASSERT(a_mb_type_sad[1] >= 0);
/*THis calclates sum of Qps of all MBs as per the corresponding mb type*/
/*THis is different from a_mb_in_type,a_mb_type_sad and a_mb_type_tex_bits*/
a_mb_type_qp_q6[0] = ((LWORD64)i4_avg_frame_qp_q6) * a_mb_in_type[0];
a_mb_type_qp_q6[1] = ((LWORD64)i4_avg_frame_qp_q6) * a_mb_in_type[1];
{
WORD32 i4_avg_qp_q6_without_offset = 0, i4_hevc_qp_rc = i4_avg_frame_hevc_qp;
WORD32 i4_rc_pic_type_rc_for_offset = rc_pic_type;
if(i4_rc_pic_type_rc_for_offset > B2_PIC)
i4_rc_pic_type_rc_for_offset = i4_rc_pic_type_rc_for_offset - B2_PIC;
i4_hevc_qp_rc = i4_hevc_qp_rc - ps_rc_lap_out->ai4_offsets[i4_rc_pic_type_rc_for_offset] +
ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset;
i4_hevc_qp_rc =
CLIP3(i4_hevc_qp_rc, 1, MAX_HEVC_QP + ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset);
i4_avg_qp_q6_without_offset =
ps_rc_ctxt->ps_rc_quant_ctxt->pi4_qp_to_qscale_q_factor[i4_hevc_qp_rc];
/*Store the HBD qscale with and without accounting for offset*/
s_frame_info.f_hbd_q_scale_without_offset =
(float)i4_avg_qp_q6_without_offset / (1 << QSCALE_Q_FAC);
s_frame_info.f_hbd_q_scale = (float)i4_avg_frame_qp_q6 / (1 << QSCALE_Q_FAC);
s_frame_info.i4_num_entries++;
s_frame_info.i4_num_entries++;
/*Store the 8 bit qscale with and without accounting for offset*/
/*Can be useful for pre-enc stage*/
if(ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset != 0)
{
s_frame_info.f_8bit_q_scale_without_offset =
s_frame_info.f_hbd_q_scale_without_offset / (1 << (ps_rc_ctxt->u1_bit_depth - 8));
s_frame_info.f_8bit_q_scale =
s_frame_info.f_hbd_q_scale / (1 << (ps_rc_ctxt->u1_bit_depth - 8));
}
else
{
s_frame_info.f_8bit_q_scale_without_offset = s_frame_info.f_hbd_q_scale_without_offset;
s_frame_info.f_8bit_q_scale = s_frame_info.f_hbd_q_scale;
}
s_frame_info.i4_num_entries++;
s_frame_info.i4_num_entries++;
}
/*making intra cost same as ssd as of now*/
i4_intra_cost = u4_frame_intra_sad;
/* Handling bits stuffing and skips */
{
WORD32 i4_num_bits_to_prevent_vbv_underflow;
vbv_buf_status_e vbv_buffer_status;
vbv_buffer_status = get_buffer_status(
ps_rc_ctxt->rc_hdl,
u4_total_bits_consumed,
rc_pic_type, //the picture type convention is different in buffer handling
&i4_num_bits_to_prevent_vbv_underflow);
if(vbv_buffer_status == VBV_UNDERFLOW)
{
}
if(vbv_buffer_status == VBV_OVERFLOW)
{
i4_bits_to_be_stuffed =
get_bits_to_stuff(ps_rc_ctxt->rc_hdl, u4_total_bits_consumed, rc_pic_type);
//i4_bits_to_be_stuffed = 0;/*STORAGE_RC*/
}
}
{
WORD32 ai4_sad[MAX_PIC_TYPE], i4_valid_sad_entry = 0;
UWORD32 u4_avg_sad = 0;
/*calculate frame complexity. Given same content frame complexity should not vary across I,P and Bpic. Hence frame complexity is calculated
based on average of all pic types SAD*/
if(rc_pic_type == I_PIC)
{
ai4_sad[I_PIC] = u4_frame_intra_sad;
}
else
{
/*call to get previous I-PIC sad*/
rc_get_sad(ps_rc_ctxt->rc_hdl, &ai4_sad[0]);
}
/*since intra sad is not available for every frame use previous I pic intra frame SAD*/
rc_put_sad(ps_rc_ctxt->rc_hdl, ai4_sad[I_PIC], u4_frame_sad, rc_pic_type);
rc_get_sad(ps_rc_ctxt->rc_hdl, &ai4_sad[0]);
/*for first few frame valid SAD is not available. This will make sure invalid data is not used*/
if(ps_rc_ctxt->i4_field_pic == 0)
{
for(i = 0; i < ps_rc_ctxt->i4_num_active_pic_type; i++)
{
if(ai4_sad[i] >= 0)
{
u4_avg_sad += ai4_sad[i];
i4_valid_sad_entry++;
}
}
}
else /*for field case*/
{
if(ai4_sad[0] >= 0)
{
u4_avg_sad += ai4_sad[0];
i4_valid_sad_entry++;
}
for(i = 1; i < ps_rc_ctxt->i4_num_active_pic_type; i++)
{
if(ai4_sad[i] >= 0)
{
u4_avg_sad += ai4_sad[i];
i4_valid_sad_entry++;
}
if(ai4_sad[i + FIELD_OFFSET] >= 0)
{
u4_avg_sad += ai4_sad[i + FIELD_OFFSET];
i4_valid_sad_entry++;
}
}
}
if(i4_valid_sad_entry > 0)
{
i4_frame_complexity =
(u4_avg_sad) /
(i4_valid_sad_entry * (ps_rc_ctxt->i4_frame_width * ps_rc_ctxt->i4_frame_height));
}
else
{
i4_frame_complexity = 1;
}
}
ASSERT(i4_frame_complexity >= 0);
/*I_model only reset In case of fade-in and fade-out*/
if(ps_rc_ctxt->ai4_I_model_only_reset[i4_enc_frm_id])
{
ASSERT(rc_pic_type == I_PIC);
rc_reset_pic_model(ps_rc_ctxt->rc_hdl, I_PIC);
ps_rc_ctxt->ai4_I_model_only_reset[i4_enc_frm_id] = 0;
}
/*check if next picture is I frame, both scene cuts and I pictures are treated as end of period*/
{
if(ps_rc_lap_out->i4_rc_pic_type != -1 && ps_rc_lap_out->i4_rc_scene_type != -1)
{
if(ps_rc_ctxt->u4_intra_frame_interval != 1)
{
/*TBD: For second pass this should be only criteria, While merging to latest verison make sure non - I SCD is not considered as one of the condition*/
i4_is_last_frm_period = (WORD32)(
ps_rc_lap_out->i4_next_pic_type == IV_IDR_FRAME ||
ps_rc_lap_out->i4_next_pic_type == IV_I_FRAME);
}
else
{
i4_is_last_frm_period =
(WORD32)(ps_rc_lap_out->i4_next_scene_type == SCENE_TYPE_SCENE_CUT);
}
}
/*In two pass only I frame ending should be considered end of period, otherwise complexity changes should be allowed to reset model in CBR and VBR modes*/
if(ps_rc_ctxt->i4_rc_pass != 2)
i4_is_last_frm_period = i4_is_last_frm_period ||
ps_rc_ctxt->ai4_is_cmplx_change_reset_bits[i4_enc_frm_id];
}
#if 1 //FRAME_PARALLEL_LVL //ELP_RC
ps_rc_ctxt->i4_est_text_bits_ctr_update_qp++;
ps_rc_ctxt->i4_est_text_bits_ctr_update_qp =
(ps_rc_ctxt->i4_est_text_bits_ctr_update_qp % (ps_rc_ctxt->i4_num_frame_parallel));
#endif
update_frame_level_info(
ps_rc_ctxt->rc_hdl,
rc_pic_type,
a_mb_type_sad,
u4_total_bits_consumed, /*total bits consumed by frame*/
u4_total_header_bits,
a_mb_type_tex_bits,
a_mb_type_qp_q6, /*sum of qp of all mb in frame, since no ctb level modulation*/
a_mb_in_type,
i4_avg_activity,
ps_rc_ctxt->ai4_is_frame_scd[i4_enc_frm_id], /*currenlty SCD is not enabled*/
0, /*not a pre encode skip*/
i4_intra_cost,
0,
ps_rc_lap_out
->i4_ignore_for_rc_update, /*HEVC_hierarchy: do not supress update for non-ref B pic*/
i4_bits_to_be_stuffed,
(ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id] ||
ps_rc_ctxt->ai4_is_non_I_scd_pic[i4_enc_frm_id] ||
ps_rc_ctxt->ai4_is_cmplx_change_reset_model[i4_enc_frm_id]),
ps_rc_ctxt->ai4_lap_complexity_q7[i4_enc_frm_id],
i4_is_last_frm_period,
ps_rc_ctxt->ai4_is_cmplx_change_reset_bits[i4_enc_frm_id],
&s_frame_info,
ps_rc_lap_out->i4_is_rc_model_needs_to_be_updated,
ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset,
i4_scene_num,
ps_rc_ctxt->ai4_scene_numbers[i4_scene_num],
ps_rc_ctxt->i4_est_text_bits_ctr_update_qp);
/** reset flags valid for only one frame*/
ps_rc_ctxt->ai4_is_frame_scd[i4_enc_frm_id] = 0;
ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id] = 0;
ps_rc_ctxt->ai4_is_non_I_scd_pic[i4_enc_frm_id] = 0;
ps_rc_ctxt->ai4_is_cmplx_change_reset_model[i4_enc_frm_id] = 0;
ps_rc_ctxt->ai4_is_cmplx_change_reset_bits[i4_enc_frm_id] = 0;
ps_rc_ctxt->i4_is_first_frame_encoded = 1;
/** update the scene num for current frame*/
ps_rc_ctxt->au4_scene_num_temp_id[ps_rc_lap_out->i4_rc_temporal_lyr_id] =
ps_rc_lap_out->u4_rc_scene_num;
if(ps_rc_ctxt->ai4_is_frame_scd[i4_enc_frm_id])
{
/*reset pre-enc SAD whenever SCD is detected so that it does not detect scene cut for other pictures*/
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[i] = -1;
}
}
/*remember i frame's cost metric to scale SAD of next of I frame*/
if(pic_type == IV_I_FRAME || pic_type == IV_IDR_FRAME)
{
ps_rc_ctxt->i8_prev_i_frm_cost = ps_rc_ctxt->ai8_cur_frm_intra_cost[i4_enc_frm_id];
ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[rc_pic_type] =
ps_rc_ctxt->ai8_cur_frm_intra_cost[i4_enc_frm_id];
}
/*for other picture types update hme cost*/
else
{
ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[rc_pic_type] =
ps_rc_ctxt->ai8_cur_frame_coarse_ME_cost[i4_enc_frm_id];
}
}
/*!
******************************************************************************
* \if Function name : ihevce_rc_interface_update \endif
*
* \brief
* Updating rate control interface parameters after the query call.
*
* \param[in] Rate control interface context,
* Picture Type
* Lap out structure pointer
*
*
* \return
* None
*
* \author Ittiam
* Ittiam
*
*****************************************************************************
*/
void ihevce_rc_interface_update(
void *pv_ctxt,
IV_PICTURE_CODING_TYPE_T pic_type,
rc_lap_out_params_t *ps_rc_lap_out,
WORD32 i4_avg_frame_hevc_qp,
WORD32 i4_enc_frm_id)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
picture_type_e rc_pic_type = ihevce_rc_conv_pic_type(
pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
WORD32 i;
WORD32 i4_avg_frame_qp_q6, i4_ctr = -1, i4_i, i4_j;
WORD32 i4_scene_num = ps_rc_lap_out->u4_rc_scene_num % MAX_SCENE_NUM;
/*store frame qp to clip qp accordingly*/
if(ps_rc_lap_out->i4_is_rc_model_needs_to_be_updated)
{
WORD32 i4_i, i4_temp_i_qp, i4_temp_qp;
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][rc_pic_type] = i4_avg_frame_hevc_qp;
ps_rc_ctxt->ai4_scene_numbers[i4_scene_num]++;
if(rc_pic_type < P1_PIC)
i4_temp_i_qp = i4_avg_frame_hevc_qp - rc_pic_type;
else
i4_temp_i_qp = i4_avg_frame_hevc_qp - rc_pic_type + 4;
i4_temp_i_qp = ihevce_clip_min_max_qp(ps_rc_ctxt, i4_temp_i_qp, I_PIC, 0);
if(ps_rc_ctxt->ai4_scene_numbers[i4_scene_num] == 1)
{
for(i4_i = 0; i4_i < 5; i4_i++)
{
if(ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][i4_i] == INIT_HEVCE_QP_RC)
{
i4_temp_qp = i4_temp_i_qp + i4_i;
i4_temp_qp = ihevce_clip_min_max_qp(
ps_rc_ctxt, i4_temp_qp, (picture_type_e)i4_i, MAX(i4_i - 1, 0));
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][i4_i] = i4_temp_qp;
if(i4_i > 0)
ps_rc_ctxt->ai4_prev_pic_hevc_qp[i4_scene_num][i4_i + 4] = i4_temp_qp;
}
}
}
}
for(i4_i = 0; i4_i < MAX_NON_REF_B_PICS_IN_QUEUE_SGI; i4_i++)
{
if(ps_rc_lap_out->u4_rc_scene_num == ps_rc_ctxt->au4_prev_scene_num_multi_scene[i4_i])
{
i4_ctr = i4_i;
break;
}
}
if(-1 == i4_ctr)
{
ps_rc_ctxt->i4_prev_qp_ctr++;
ps_rc_ctxt->i4_prev_qp_ctr = ps_rc_ctxt->i4_prev_qp_ctr % MAX_NON_REF_B_PICS_IN_QUEUE_SGI;
i4_ctr = ps_rc_ctxt->i4_prev_qp_ctr;
ps_rc_ctxt->au4_prev_scene_num_multi_scene[i4_ctr] = ps_rc_lap_out->u4_rc_scene_num;
for(i4_j = 0; i4_j < MAX_PIC_TYPE; i4_j++)
{
ps_rc_ctxt->ai4_qp_for_previous_scene_multi_scene[i4_ctr][i4_j] = 0;
}
}
{
ps_rc_ctxt->ai4_qp_for_previous_scene_multi_scene[i4_ctr][rc_pic_type] =
i4_avg_frame_hevc_qp;
}
/*I_model only reset In case of fade-in and fade-out*/
if(ps_rc_ctxt->ai4_I_model_only_reset[i4_enc_frm_id])
{
ASSERT(rc_pic_type == I_PIC);
rc_reset_pic_model(ps_rc_ctxt->rc_hdl, I_PIC);
ps_rc_ctxt->ai4_I_model_only_reset[i4_enc_frm_id] = 0;
}
i4_avg_frame_qp_q6 = ps_rc_ctxt->ps_rc_quant_ctxt->pi4_qp_to_qscale_q_factor
[i4_avg_frame_hevc_qp + ps_rc_ctxt->ps_rc_quant_ctxt->i1_qp_offset];
update_frame_rc_get_frame_qp_info(
ps_rc_ctxt->rc_hdl,
rc_pic_type,
ps_rc_ctxt->ai4_is_frame_scd[i4_enc_frm_id],
(ps_rc_ctxt->ai4_is_pause_to_resume[i4_enc_frm_id] ||
ps_rc_ctxt->ai4_is_non_I_scd_pic[i4_enc_frm_id] ||
ps_rc_ctxt->ai4_is_cmplx_change_reset_model[i4_enc_frm_id]),
i4_avg_frame_qp_q6,
ps_rc_lap_out->i4_ignore_for_rc_update,
i4_scene_num,
ps_rc_ctxt->ai4_scene_numbers[i4_scene_num]);
/** update the scene num for current frame*/
ps_rc_ctxt->au4_scene_num_temp_id[ps_rc_lap_out->i4_rc_temporal_lyr_id] =
ps_rc_lap_out->u4_rc_scene_num;
if(ps_rc_ctxt->ai4_is_frame_scd[i4_enc_frm_id])
{
/*reset pre-enc SAD whenever SCD is detected so that it does not detect scene cut for other pictures*/
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[i] = -1;
}
}
/*remember i frame's cost metric to scale SAD of next of I frame*/
if(pic_type == IV_I_FRAME || pic_type == IV_IDR_FRAME)
{
ps_rc_ctxt->i8_prev_i_frm_cost = ps_rc_ctxt->ai8_cur_frm_intra_cost[i4_enc_frm_id];
ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[rc_pic_type] =
ps_rc_ctxt->ai8_cur_frm_intra_cost[i4_enc_frm_id];
}
/*for other picture types update hme cost*/
else
{
ps_rc_ctxt->ai8_prev_frm_pre_enc_cost[rc_pic_type] =
ps_rc_ctxt->ai8_cur_frame_coarse_ME_cost[i4_enc_frm_id];
}
ps_rc_ctxt->i4_is_first_frame_encoded = 1;
}
/****************************************************************************
Function Name : ihevce_rc_store_retrive_update_info
Description : for storing and retrieving the data in case of the Enc Loop Parallelism.
Inputs :
Globals :
Processing :
Outputs :
Returns :
Issues :
Revision History:
DD MM YYYY Author(s) Changes (Describe the changes made)
*****************************************************************************/
void ihevce_rc_store_retrive_update_info(
void *pv_ctxt,
rc_bits_sad_t *ps_rc_frame_stat,
WORD32 i4_enc_frm_id_rc,
WORD32 bit_rate_id,
WORD32 i4_store_retrive,
WORD32 *pout_buf_id,
WORD32 *pi4_rc_pic_type,
WORD32 *pcur_qp,
void *ps_lap_out,
void *ps_rc_lap_out)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
if(1 == i4_store_retrive)
{
memcpy(
&ps_rc_ctxt->as_rc_frame_stat_store[i4_enc_frm_id_rc][bit_rate_id],
ps_rc_frame_stat,
sizeof(rc_bits_sad_t));
memcpy(&ps_rc_ctxt->out_buf_id[i4_enc_frm_id_rc][bit_rate_id], pout_buf_id, sizeof(WORD32));
memcpy(&ps_rc_ctxt->i4_pic_type[i4_enc_frm_id_rc], pi4_rc_pic_type, sizeof(WORD32));
memcpy(&ps_rc_ctxt->cur_qp[i4_enc_frm_id_rc][bit_rate_id], pcur_qp, sizeof(WORD32));
memcpy(
&ps_rc_ctxt->as_lap_out[i4_enc_frm_id_rc],
ps_lap_out,
sizeof(ihevce_lap_output_params_t));
memcpy(
&ps_rc_ctxt->as_rc_lap_out[i4_enc_frm_id_rc],
ps_rc_lap_out,
sizeof(rc_lap_out_params_t));
{
rc_lap_out_params_t *ps_rc_lap_out_curr = (rc_lap_out_params_t *)ps_rc_lap_out;
rc_lap_out_params_t *ps_rc_lap_out_next_encode =
(rc_lap_out_params_t *)ps_rc_lap_out_curr->ps_rc_lap_out_next_encode;
if(NULL != ps_rc_lap_out_next_encode)
{
ps_rc_ctxt->as_rc_lap_out[i4_enc_frm_id_rc].i4_next_pic_type =
ps_rc_lap_out_next_encode->i4_rc_pic_type;
ps_rc_ctxt->as_rc_lap_out[i4_enc_frm_id_rc].i4_next_scene_type =
ps_rc_lap_out_next_encode->i4_rc_scene_type;
}
else
{
if(ps_rc_ctxt->u4_intra_frame_interval <= 1 ||
(ps_rc_lap_out_curr->i4_rc_display_num &&
(ps_rc_lap_out_curr->i4_rc_display_num %
(ps_rc_ctxt->u4_intra_frame_interval - 1)) == 0))
{
ps_rc_ctxt->as_rc_lap_out[i4_enc_frm_id_rc].i4_next_pic_type = IV_I_FRAME;
}
else
{
ps_rc_ctxt->as_rc_lap_out[i4_enc_frm_id_rc].i4_next_pic_type = -1;
}
ps_rc_ctxt->as_rc_lap_out[i4_enc_frm_id_rc].i4_next_scene_type = -1;
}
ps_rc_ctxt->as_rc_lap_out[i4_enc_frm_id_rc].ps_rc_lap_out_next_encode = NULL;
}
}
else if(2 == i4_store_retrive)
{
memcpy(
ps_rc_frame_stat,
&ps_rc_ctxt->as_rc_frame_stat_store[i4_enc_frm_id_rc][bit_rate_id],
sizeof(rc_bits_sad_t));
memcpy(pout_buf_id, &ps_rc_ctxt->out_buf_id[i4_enc_frm_id_rc][bit_rate_id], sizeof(WORD32));
memcpy(pi4_rc_pic_type, &ps_rc_ctxt->i4_pic_type[i4_enc_frm_id_rc], sizeof(WORD32));
memcpy(pcur_qp, &ps_rc_ctxt->cur_qp[i4_enc_frm_id_rc][bit_rate_id], sizeof(WORD32));
memcpy(
ps_lap_out,
&ps_rc_ctxt->as_lap_out[i4_enc_frm_id_rc],
sizeof(ihevce_lap_output_params_t));
memcpy(
ps_rc_lap_out,
&ps_rc_ctxt->as_rc_lap_out[i4_enc_frm_id_rc],
sizeof(rc_lap_out_params_t));
}
else
{
ASSERT(0);
}
}
/*###############################################*/
/******* END OF RC UPDATE FUNCTIONS **************/
/*###############################################*/
/*#################################################*/
/******* START OF RC UTILS FUNCTIONS **************/
/*#################################################*/
/**
******************************************************************************
*
* @brief function to account for error correction between bits rdopt estimate
* and actual entropy bit generation
*
* @par Description
*
* @param[in] pv_rc_ctxt
* void pointer to rc ctxt
* @param[in] i4_rdopt_bits_gen_error
* WODd32 variable with error correction between rdopt and entropy bytes gen
*
* @return void
*
******************************************************************************
*/
void ihevce_rc_rdopt_entropy_bit_correct(
void *pv_rc_ctxt, WORD32 i4_cur_entropy_consumption, WORD32 i4_buf_id)
{
rc_context_t *ps_ctxt = (rc_context_t *)pv_rc_ctxt;
WORD32 i4_error;
WORD32 i, count = 0;
ASSERT(i4_buf_id >= 0);
ps_ctxt->ai4_entropy_bit_consumption[ps_ctxt->i4_entropy_bit_count] =
i4_cur_entropy_consumption;
ps_ctxt->ai4_entropy_bit_consumption_buf_id[ps_ctxt->i4_entropy_bit_count] = i4_buf_id;
ps_ctxt->i4_entropy_bit_count = (ps_ctxt->i4_entropy_bit_count + 1) % NUM_BUF_RDOPT_ENT_CORRECT;
for(i = 0; i < NUM_BUF_RDOPT_ENT_CORRECT; i++)
{
if(ps_ctxt->ai4_rdopt_bit_consumption_buf_id[i] >= 0 &&
(ps_ctxt->ai4_rdopt_bit_consumption_buf_id[i] ==
ps_ctxt->ai4_entropy_bit_consumption_buf_id[i]))
{
i4_error = ps_ctxt->ai4_rdopt_bit_consumption_estimate[i] -
ps_ctxt->ai4_entropy_bit_consumption[i];
//DBG_PRINTF("entropy mismatch error = %d\n",i4_error/ps_ctxt->ai4_rdopt_bit_consumption_estimate[i]);
ps_ctxt->ai4_rdopt_bit_consumption_estimate[i] = -1;
ps_ctxt->ai4_rdopt_bit_consumption_buf_id[i] = -1;
ps_ctxt->ai4_entropy_bit_consumption[i] = -1;
ps_ctxt->ai4_entropy_bit_consumption_buf_id[i] = -1;
/*accumulate mismatch along with gop level bit error that is propogated to next frame*/
/*error = rdopt - entropy so it is expected to be negative*/
rc_update_mismatch_error(ps_ctxt->rc_hdl, i4_error);
count++;
}
}
}
/**
******************************************************************************
*
* @name ihevce_rc_check_non_lap_scd
*
* @par Description Detects SCD frames as I_only_scds or non_I_scds based
on intrasatd & ME costs. Updates scd flags
*
* @param[in] ps_rc_ctxt - pointer to rc context
* ps_rc_lap_out
* @return void
*
******************************************************************************
*/
void ihevce_rc_check_non_lap_scd(void *pv_rc_ctxt, rc_lap_out_params_t *ps_rc_lap_out)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
picture_type_e rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_rc_lap_out->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
/*Init to normal frames*/
ps_rc_lap_out->i4_is_I_only_scd = 0;
ps_rc_lap_out->i4_is_non_I_scd = 0;
/*None of the above check is valid if marked as scene cut*/
if(ps_rc_lap_out->i4_rc_scene_type == SCENE_TYPE_SCENE_CUT)
{
WORD32 i;
/*reset all older data*/
for(i = 0; i < MAX_PIC_TYPE; i++)
{
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_I_intra_raw_satd[i] = -1;
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_cost[i] = -1;
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_sad[i] = -1;
}
}
else
{
/*Check if it is I only reset case, lap_out is assumed to have latest data which is used to set the corresponding flags*/
/*For I pic check for I only reset case and for other pictures check for non-I scd case*/
if(rc_pic_type == I_PIC)
{
if(ps_rc_lap_out->i8_pre_intra_satd <
(ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_I_intra_raw_satd[rc_pic_type] >> 1) ||
ps_rc_lap_out->i8_pre_intra_satd >
(ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_I_intra_raw_satd[rc_pic_type] << 1))
{
/*Check if atleast one frame data is available*/
if(ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_I_intra_raw_satd[rc_pic_type] >= 0)
ps_rc_lap_out->i4_is_I_only_scd = 1;
}
}
else if(
((rc_pic_type == P_PIC) &&
(ps_rc_lap_out->i4_rc_quality_preset == IHEVCE_QUALITY_P6)) ||
(ps_rc_lap_out->i4_rc_quality_preset < IHEVCE_QUALITY_P6))
{
#define SAD_THREASHOLD_30FPS (2.5)
/*Choose threshold as 2.5 for 30 fps content and 1.75 for 60 fps. Scale accordingly for intermediate framerate*/
WORD32 i4_non_simple_repeat_prev_frame_detect = 0;
float sad_change_threshold =
(float)(-0.8f * ((float)ps_rc_ctxt->u4_max_frame_rate / 30000) + 3.05f); /*Change of SAD threshold for 30 fps content, this should be lowered for 60 fps*/
if(sad_change_threshold < 1.5f)
sad_change_threshold = 1.5f;
if(sad_change_threshold > 3.0f)
sad_change_threshold = 3.0f;
ASSERT(ps_rc_lap_out->i8_raw_l1_coarse_me_sad >= 0);
/*block variance computed at 4x4 level in w/4*h/4,
percent dc blks is how many block's variance are less than or equal to 16*/
if(ps_rc_lap_out->i4_perc_dc_blks < 85)
{
/*me sad is expected to be zero for repeat frames*/
if((ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_sad[rc_pic_type] ==
0) &&
(ps_rc_lap_out->i4_rc_temporal_lyr_id == ps_rc_ctxt->i4_max_temporal_lyr))
{
i4_non_simple_repeat_prev_frame_detect = 1;
}
}
if(ps_rc_lap_out->i8_frame_acc_coarse_me_cost >
(sad_change_threshold *
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_cost[rc_pic_type]) &&
(ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_cost[rc_pic_type] >= 0) &&
(!i4_non_simple_repeat_prev_frame_detect))
{
WORD32 one_per_pixel_sad_L1;
/*per pixel sad has to be greater than 1 to avoid repeat frames influence non-I scd detection*/
if((ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width) < 4000000)
{
/*1080*/
one_per_pixel_sad_L1 =
(ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width) >> 2;
}
else
{
/*4k*/
one_per_pixel_sad_L1 =
(ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width) >> 4;
}
if(ps_rc_lap_out->i8_frame_acc_coarse_me_cost > one_per_pixel_sad_L1)
{
{
ps_rc_lap_out->i4_is_non_I_scd = 1;
}
}
}
if(rc_pic_type == P_PIC)
{
if(ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_cost[rc_pic_type] < 0)
{
if(ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_I_intra_raw_satd[I_PIC] > 0)
{
if(ps_rc_lap_out->i8_pre_intra_satd >
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_I_intra_raw_satd[I_PIC] << 1)
{
ps_rc_lap_out->i4_is_non_I_scd = 1;
}
}
}
}
}
}
/*remember the previous frame stats*/
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_I_intra_raw_satd[rc_pic_type] =
ps_rc_lap_out->i8_pre_intra_satd; //ps_rc_lap_out->i8_pre_intra_satd;
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_cost[rc_pic_type] =
ps_rc_lap_out->i8_frame_acc_coarse_me_cost; //ps_rc_lap_out->i8_frame_acc_coarse_me_sad;
ps_rc_ctxt->s_l1_state_metric.ai8_L1_prev_pic_coarse_me_sad[rc_pic_type] =
ps_rc_lap_out->i8_raw_l1_coarse_me_sad;
}
/**
******************************************************************************
*
* @name ihevce_rc_check_is_pre_enc_qp_valid
*
* @par Description checking whether enc thread has updated qp in reverse queue
*
* @param[in] ps_rc_ctxt - pointer to rc context
*
* @return zero on success
*
******************************************************************************
*/
/**only function accessed by encoder without using mutex lock*/
WORD32 ihevce_rc_check_is_pre_enc_qp_valid(void *pv_rc_ctxt, volatile WORD32 *pi4_force_end_flag)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
volatile WORD32 i4_is_qp_valid;
volatile WORD32 *pi4_is_qp_valid;
pi4_is_qp_valid =
(volatile WORD32 *)&ps_rc_ctxt->as_pre_enc_qp_queue[ps_rc_ctxt->i4_pre_enc_qp_read_index]
.i4_is_qp_valid;
i4_is_qp_valid = *pi4_is_qp_valid;
/*Due to stagger between L1 IPE and L0 IPE, towards the end (when encoder is in flush mode) L0 IPE can race ahead of enc
since it will suddenly get stagger between L1 and L0 worth of free buffers. It could try to start L0 even before enc has
populated qp for such frames. qp = -1 is returned in such case which implies encoder should wait for qp to be pop*/
while(i4_is_qp_valid == -1)
{
/*this rate control call is outside mutex lock to avoid deadlock. If this acquires mutex lock enc will not be able to
populate qp*/
i4_is_qp_valid = *pi4_is_qp_valid;
if(1 == (*pi4_force_end_flag))
{
*pi4_is_qp_valid = 1;
i4_is_qp_valid = 1;
}
}
return 0;
}
/*!
******************************************************************************
* \if Function name : ihevce_compute_temporal_complexity_reset_Kp_Kb
*
* \brief
*
* \param[in] *pv_ctxt -> rc context
*
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
void ihevce_compute_temporal_complexity_reset_Kp_Kb(
rc_lap_out_params_t *ps_rc_lap_out, void *pv_rc_ctxt, WORD32 i4_Kp_Kb_reset_flag)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
rc_lap_out_params_t *ps_cur_rc_lap_out_temporal_offset,
*ps_cur_rc_lap_out_temporal_offset_scd_detect;
picture_type_e curr_rc_pic_type;
LWORD64 i8_total_acc_coarse_me_sad = 0, i8_avg_acc_coarse_me_sad = 0;
WORD8 i1_num_frames_in_Sub_GOP = 0, i = 0, i1_no_reset = 0;
WORD32 i4_inter_frame_interval = rc_get_inter_frame_interval(ps_rc_ctxt->rc_hdl);
WORD32 i4_frame_qp = 0, i4_temp_frame_qp = 0;
WORD32 ai4_offsets[5] = { -3, -2, 2, 6, 7 };
ps_cur_rc_lap_out_temporal_offset = ps_rc_lap_out;
ps_cur_rc_lap_out_temporal_offset_scd_detect = ps_rc_lap_out;
curr_rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_cur_rc_lap_out_temporal_offset->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_cur_rc_lap_out_temporal_offset->i4_rc_temporal_lyr_id,
ps_cur_rc_lap_out_temporal_offset->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
if(curr_rc_pic_type == I_PIC)
{
ps_cur_rc_lap_out_temporal_offset_scd_detect =
(rc_lap_out_params_t *)ps_cur_rc_lap_out_temporal_offset->ps_rc_lap_out_next_encode;
ps_cur_rc_lap_out_temporal_offset =
(rc_lap_out_params_t *)ps_cur_rc_lap_out_temporal_offset->ps_rc_lap_out_next_encode;
if(NULL != ps_cur_rc_lap_out_temporal_offset)
{
curr_rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_cur_rc_lap_out_temporal_offset->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_cur_rc_lap_out_temporal_offset->i4_rc_temporal_lyr_id,
ps_cur_rc_lap_out_temporal_offset->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
}
else
return;
}
if(ps_cur_rc_lap_out_temporal_offset->i4_L1_qp == -1)
return;
if(ps_cur_rc_lap_out_temporal_offset->i4_L0_qp == -1)
i4_frame_qp = ps_cur_rc_lap_out_temporal_offset->i4_L1_qp;
else
i4_frame_qp = ps_cur_rc_lap_out_temporal_offset->i4_L0_qp;
i1_num_frames_in_Sub_GOP = 0;
i = 0;
i1_no_reset = 0;
do
{
if(ps_cur_rc_lap_out_temporal_offset != NULL)
{
if(curr_rc_pic_type != I_PIC)
i4_temp_frame_qp =
i4_frame_qp + ps_cur_rc_lap_out_temporal_offset->i4_rc_temporal_lyr_id + 1;
i4_temp_frame_qp += ai4_offsets[curr_rc_pic_type];
i4_temp_frame_qp = CLIP3(i4_temp_frame_qp, 1, 51);
{
if(curr_rc_pic_type != I_PIC)
{
i8_total_acc_coarse_me_sad +=
ps_cur_rc_lap_out_temporal_offset
->ai8_frame_acc_coarse_me_sad[i4_temp_frame_qp];
i1_num_frames_in_Sub_GOP++;
i++;
}
else
{
break;
}
}
ps_cur_rc_lap_out_temporal_offset =
(rc_lap_out_params_t *)ps_cur_rc_lap_out_temporal_offset->ps_rc_lap_out_next_encode;
if(ps_cur_rc_lap_out_temporal_offset == NULL)
{
break;
}
curr_rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_cur_rc_lap_out_temporal_offset->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_cur_rc_lap_out_temporal_offset->i4_rc_temporal_lyr_id,
ps_cur_rc_lap_out_temporal_offset->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
}
else
{
i1_num_frames_in_Sub_GOP = 0;
break;
}
} while(
((((curr_rc_pic_type != P_PIC) && ((curr_rc_pic_type != I_PIC))) ||
(curr_rc_pic_type == P_PIC)) &&
(i1_num_frames_in_Sub_GOP < i4_inter_frame_interval)));
if((i1_num_frames_in_Sub_GOP) && (i1_no_reset == 0))
{
float f_hme_sad_per_pixel;
i8_avg_acc_coarse_me_sad = (i8_total_acc_coarse_me_sad / i1_num_frames_in_Sub_GOP);
f_hme_sad_per_pixel =
((float)i8_avg_acc_coarse_me_sad /
(ps_rc_ctxt->i4_frame_height * ps_rc_ctxt->i4_frame_width));
f_hme_sad_per_pixel = CLIP3(f_hme_sad_per_pixel, 0.01f, 5.0f);
/*reset the QP offsets for the next sub GOP depending on the offline model based on the temporal complexity */
if(i4_Kp_Kb_reset_flag)
{
WORD32 i4_bin;
rc_reset_Kp_Kb(
ps_rc_ctxt->rc_hdl,
8.00,
ps_rc_ctxt->i4_num_active_pic_type,
f_hme_sad_per_pixel,
&i4_bin,
ps_rc_ctxt->i4_rc_pass);
}
else
{
rc_ba_get_qp_offset_offline_data(
ps_rc_ctxt->rc_hdl,
ps_rc_lap_out->ai4_offsets,
f_hme_sad_per_pixel,
ps_rc_ctxt->i4_num_active_pic_type,
&ps_rc_lap_out->i4_complexity_bin);
ps_cur_rc_lap_out_temporal_offset = ps_rc_lap_out;
ps_cur_rc_lap_out_temporal_offset->i4_offsets_set_flag = 1;
curr_rc_pic_type = ihevce_rc_conv_pic_type(
(IV_PICTURE_CODING_TYPE_T)ps_rc_lap_out->i4_rc_pic_type,
ps_rc_ctxt->i4_field_pic,
ps_rc_lap_out->i4_rc_temporal_lyr_id,
ps_rc_lap_out->i4_is_bottom_field,
ps_rc_ctxt->i4_top_field_first);
if((curr_rc_pic_type == I_PIC) &&
((rc_lap_out_params_t *)ps_cur_rc_lap_out_temporal_offset->ps_rc_lap_out_next_encode)
->i4_rc_pic_type == P_PIC)
i1_num_frames_in_Sub_GOP++;
for(i = 1; i < i1_num_frames_in_Sub_GOP; i++)
{
ps_cur_rc_lap_out_temporal_offset =
(rc_lap_out_params_t *)
ps_cur_rc_lap_out_temporal_offset->ps_rc_lap_out_next_encode;
memmove(
ps_cur_rc_lap_out_temporal_offset->ai4_offsets,
ps_rc_lap_out->ai4_offsets,
sizeof(WORD32) * 5);
ps_cur_rc_lap_out_temporal_offset->i4_complexity_bin =
ps_rc_lap_out->i4_complexity_bin;
ps_cur_rc_lap_out_temporal_offset->i4_offsets_set_flag = 1;
}
}
}
}
/**
******************************************************************************
*
* @brief function to get delta QP or In frame RC bits estimate to avoid buffer underflow
*
* @par Description
* @param[in]
******************************************************************************
*/
WORD32 ihevce_ebf_based_rc_correction_to_avoid_overflow(
rc_context_t *ps_rc_ctxt, rc_lap_out_params_t *ps_rc_lap_out, WORD32 *pi4_tot_bits_estimated)
{
WORD32 i4_modelQP, i4_clipQP, i4_maxEbfQP, i4_diffQP, i4_is_model_valid, i4_deltaQP = 0;
LWORD64 i8_bitsClipQP, i8_grwEbf; // i8_bitsComp;
WORD32 i4_is_offline_model_used;
WORD32 i4_vbv_buffer_size, i4_drain_rate, i4_currEbf, i4_maxEbf;
WORD32 i4_case = -1;
float f_thrsh_i_pic_delta_qp_1, f_thrsh_i_pic_delta_qp_2, f_thrsh_p_pic_delta_qp_1,
f_thrsh_p_pic_delta_qp_2;
float f_thrsh_br_pic_delta_qp_1, f_thrsh_br_pic_delta_qp_2, f_thrsh_bnr_pic_delta_qp_1,
f_thrsh_bnr_pic_delta_qp_2;
float f_vbv_thrsh_delta_qp;
/*initialization of all the variables*/
rc_init_buffer_info(
ps_rc_ctxt->rc_hdl, &i4_vbv_buffer_size, &i4_currEbf, &i4_maxEbf, &i4_drain_rate);
i4_is_model_valid = ps_rc_lap_out->i4_is_model_valid;
i4_modelQP = ps_rc_ctxt->s_rc_high_lvl_stat.i4_modelQP;
i4_clipQP = ps_rc_ctxt->s_rc_high_lvl_stat.i4_finalQP;
i4_maxEbfQP = ps_rc_ctxt->s_rc_high_lvl_stat.i4_maxEbfQP;
i8_bitsClipQP = ps_rc_ctxt->s_rc_high_lvl_stat.i8_bits_from_finalQP;
i4_is_offline_model_used = ps_rc_ctxt->s_rc_high_lvl_stat.i4_is_offline_model_used;
ASSERT(i4_clipQP != INVALID_QP);
if(ps_rc_ctxt->i4_num_frame_parallel > 1)
{
f_thrsh_i_pic_delta_qp_1 = (float)VBV_THRSH_FRM_PRLL_I_PIC_DELTA_QP_1;
f_thrsh_i_pic_delta_qp_2 = (float)VBV_THRSH_FRM_PRLL_I_PIC_DELTA_QP_2;
f_thrsh_p_pic_delta_qp_1 = (float)VBV_THRSH_FRM_PRLL_P_PIC_DELTA_QP_1;
f_thrsh_p_pic_delta_qp_2 = (float)VBV_THRSH_FRM_PRLL_P_PIC_DELTA_QP_2;
f_thrsh_br_pic_delta_qp_1 = (float)VBV_THRSH_FRM_PRLL_BR_PIC_DELTA_QP_1;
f_thrsh_br_pic_delta_qp_2 = (float)VBV_THRSH_FRM_PRLL_BR_PIC_DELTA_QP_2;
f_thrsh_bnr_pic_delta_qp_1 = (float)VBV_THRSH_FRM_PRLL_BNR_PIC_DELTA_QP_1;
f_thrsh_bnr_pic_delta_qp_2 = (float)VBV_THRSH_FRM_PRLL_BNR_PIC_DELTA_QP_2;
f_vbv_thrsh_delta_qp = (float)VBV_THRSH_FRM_PRLL_DELTA_QP;
}
else
{
f_thrsh_i_pic_delta_qp_1 = (float)VBV_THRSH_I_PIC_DELTA_QP_1;
f_thrsh_i_pic_delta_qp_2 = (float)VBV_THRSH_I_PIC_DELTA_QP_2;
f_thrsh_p_pic_delta_qp_1 = (float)VBV_THRSH_P_PIC_DELTA_QP_1;
f_thrsh_p_pic_delta_qp_2 = (float)VBV_THRSH_P_PIC_DELTA_QP_2;
f_thrsh_br_pic_delta_qp_1 = (float)VBV_THRSH_BR_PIC_DELTA_QP_1;
f_thrsh_br_pic_delta_qp_2 = (float)VBV_THRSH_BR_PIC_DELTA_QP_2;
f_thrsh_bnr_pic_delta_qp_1 = (float)VBV_THRSH_BNR_PIC_DELTA_QP_1;
f_thrsh_bnr_pic_delta_qp_2 = (float)VBV_THRSH_BNR_PIC_DELTA_QP_2;
f_vbv_thrsh_delta_qp = (float)VBV_THRSH_DELTA_QP;
}
/* function logic starts */
if(i4_is_model_valid)
{
ASSERT(i4_modelQP != INVALID_QP);
i8_grwEbf = i8_bitsClipQP - (LWORD64)i4_drain_rate;
if(((i4_currEbf + i8_grwEbf) > (0.6*i4_vbv_buffer_size)) /*&&
i4_modelQP >= i4_clipQP*/)
{
/* part of existing scene (i.e. no new scene)
In which case this is not first I/P/Bref/Bnref etc
The models for I/P/Bref/Bnref are all valid*/
if(((i4_currEbf + i8_grwEbf) <
i4_maxEbf)) /* does not matter whether this is 2pass, 1 pass, VBR, CBR etc*/
{
/* clipQP has been determined keeping in view certain other quality constraints like pusling etc.
So better to honour it if possible*/
//if (i8_bitsClipQP > i8_drain_rate)
{
LWORD64 i8_thrsh_for_deltaQP_2 = i4_vbv_buffer_size,
i8_thrsh_for_deltaQP_1 = i4_vbv_buffer_size;
/*even when (modelQP - clipQP) = 0, we intend to QP increase as expected ebf is above 60%*/
i4_diffQP = MAX(i4_modelQP - i4_clipQP, 1);
switch(ps_rc_lap_out->i4_rc_pic_type)
{
case IV_I_FRAME:
case IV_IDR_FRAME:
{
i8_thrsh_for_deltaQP_1 =
(LWORD64)(f_thrsh_i_pic_delta_qp_1 * i4_vbv_buffer_size);
i8_thrsh_for_deltaQP_2 =
(LWORD64)(f_thrsh_i_pic_delta_qp_2 * i4_vbv_buffer_size);
break;
}
case IV_P_FRAME:
{
i8_thrsh_for_deltaQP_1 =
(LWORD64)(f_thrsh_p_pic_delta_qp_1 * i4_vbv_buffer_size);
i8_thrsh_for_deltaQP_2 =
(LWORD64)(f_thrsh_p_pic_delta_qp_2 * i4_vbv_buffer_size);
break;
}
case IV_B_FRAME:
{
if(ps_rc_lap_out->i4_rc_is_ref_pic)
{
i8_thrsh_for_deltaQP_1 =
(LWORD64)(f_thrsh_br_pic_delta_qp_1 * i4_vbv_buffer_size);
i8_thrsh_for_deltaQP_2 =
(LWORD64)(f_thrsh_br_pic_delta_qp_2 * i4_vbv_buffer_size);
}
else
{
/*as of now using the same thresholds as B reference, later may have to tune if required*/
i8_thrsh_for_deltaQP_1 =
(LWORD64)(f_thrsh_bnr_pic_delta_qp_1 * i4_vbv_buffer_size);
i8_thrsh_for_deltaQP_2 =
(LWORD64)(f_thrsh_bnr_pic_delta_qp_2 * i4_vbv_buffer_size);
}
break;
}
default:
break;
}
if((i4_currEbf + i8_grwEbf) > i8_thrsh_for_deltaQP_1)
{
/*For more than 2 QP chnage this means a larger scale issue and probably needs to be handled elsewhere ?*/
i4_deltaQP =
MIN(2, i4_diffQP); /* we dont intend to change QP by more than 2 */
i4_case = 0;
}
else if((i4_currEbf + i8_grwEbf) > i8_thrsh_for_deltaQP_2)
{
i4_deltaQP = MIN(1, i4_diffQP);
i4_case = 1;
}
}
/* else if (i8_bitsClipQP > i8_drain_rate)
{
we have no correection, buffer will be healthy after this.
However, there could be one problem if the currEbf is already close to say 80% of EBF.
This means we have not reacted well early - needs to be handled?
This could be the case where it is a simple scene immediately following a complex scene
and is the I picture (not the first I since model is valid).
Is this possible - maybe, what to do - dont know?
}
*/
}
else /*(i4_clipQP < i4_maxEbfQP)*/
{
i4_deltaQP = 2;
i4_case = 2;
}
}
if((i4_currEbf + i8_grwEbf) < (0.6 * i4_vbv_buffer_size))
{
*pi4_tot_bits_estimated = i8_bitsClipQP;
}
}
else
{
if(i4_is_offline_model_used)
{
/* this can be only for non-I SCD, where we reset RC */
WORD32 i4_bits_est_for_in_frm_rc = *pi4_tot_bits_estimated;
i8_grwEbf = i4_bits_est_for_in_frm_rc - i4_drain_rate;
if((i4_currEbf + i8_grwEbf) > (f_vbv_thrsh_delta_qp * i4_vbv_buffer_size))
{
i4_bits_est_for_in_frm_rc =
i4_drain_rate + (WORD32)(0.85 * i4_vbv_buffer_size) - i4_currEbf;
/* if pi4_tot_bits_estimated becomes less than zero or less than drain rate this indiactes that we are near or above 85% of the buffer */
/* this needs a reaction */
if(i4_bits_est_for_in_frm_rc < i4_drain_rate)
{
*pi4_tot_bits_estimated =
MAX((i4_drain_rate + (WORD32)(0.95 * i4_vbv_buffer_size) - i4_currEbf),
i4_drain_rate);
i4_deltaQP = 2; /* this needs some review, needs to be handled well */
}
}
i4_case = 3;
}
else
{
i8_bitsClipQP = *pi4_tot_bits_estimated;
i8_grwEbf = i8_bitsClipQP - i4_drain_rate;
if(((i4_currEbf + i8_grwEbf) <
i4_maxEbf)) /* does not matter whether this is 2pass, 1 pass, VBR, CBR etc*/
{
/* clipQP has been determined keeping in view certain other quality constraints like pusling etc.
So better to honour it if possible*/
//if (i8_bitsClipQP > i8_drain_rate)
{
LWORD64 i8_thrsh_for_deltaQP_2 = i4_vbv_buffer_size,
i8_thrsh_for_deltaQP_1 = i4_vbv_buffer_size;
switch(ps_rc_lap_out->i4_rc_pic_type)
{
case IV_I_FRAME:
case IV_IDR_FRAME:
{
i8_thrsh_for_deltaQP_1 =
(LWORD64)(f_thrsh_i_pic_delta_qp_1 * i4_vbv_buffer_size);
i8_thrsh_for_deltaQP_2 =
(LWORD64)(f_thrsh_i_pic_delta_qp_2 * i4_vbv_buffer_size);
break;
}
case IV_P_FRAME:
{
i8_thrsh_for_deltaQP_1 =
(LWORD64)(f_thrsh_p_pic_delta_qp_1 * i4_vbv_buffer_size);
i8_thrsh_for_deltaQP_2 =
(LWORD64)(f_thrsh_p_pic_delta_qp_2 * i4_vbv_buffer_size);
break;
}
case IV_B_FRAME:
{
if(ps_rc_lap_out->i4_rc_is_ref_pic)
{
i8_thrsh_for_deltaQP_1 =
(LWORD64)(f_thrsh_br_pic_delta_qp_1 * i4_vbv_buffer_size);
i8_thrsh_for_deltaQP_2 =
(LWORD64)(f_thrsh_br_pic_delta_qp_2 * i4_vbv_buffer_size);
}
else
{
/*as of now using the same thresholds as B reference, later may have to tune if required*/
i8_thrsh_for_deltaQP_1 =
(LWORD64)(f_thrsh_bnr_pic_delta_qp_1 * i4_vbv_buffer_size);
i8_thrsh_for_deltaQP_2 =
(LWORD64)(f_thrsh_bnr_pic_delta_qp_2 * i4_vbv_buffer_size);
}
break;
}
default:
break;
}
if((i4_currEbf + i8_grwEbf) > i8_thrsh_for_deltaQP_1)
{
/*For more than 2 QP chnage this means a larger scale issue and probably needs to be handled elsewhere ?*/
i4_deltaQP = 2; /* we dont intend to change QP by more than 2 */
i4_case = 5;
}
else if((i4_currEbf + i8_grwEbf) > i8_thrsh_for_deltaQP_2)
{
i4_deltaQP = 1;
i4_case = 6;
}
}
}
else
{
i4_deltaQP = 2;
i4_case = 7;
}
}
}
return i4_deltaQP;
}
/*###############################################*/
/******* END OF RC UTILS FUNCTIONS ***************/
/*###############################################*/
/*########################################################*/
/******* START OF VBV COMPLIANCE FUNCTIONS ***************/
/*#######################################################*/
/*!
******************************************************************************
* \if Function name : ihevce_vbv_compliance_frame_level_update
*
* \brief
* this function initializes the hrd buffer level to be used for vbv compliance testing using the parameters feeded in VUI parameters
*
* \param[in] *pv_ctxt -> rc context
* i4_bits_generated -> bits generated from entropy
* i4_resolution_id -> info needed for log Dump
* i4_appln_bitrate_inst -> info needed for log Dump
* u4_cur_cpb_removal_delay_minus1 -> cbp removal delay of present frame
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
void ihevce_vbv_compliance_frame_level_update(
void *pv_rc_ctxt,
WORD32 i4_bits_generated,
WORD32 i4_resolution_id,
WORD32 i4_appln_bitrate_inst,
UWORD32 u4_cur_cpb_removal_delay_minus1)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_rc_ctxt;
float f_max_vbv_buff_size = (float)ps_rc_ctxt->s_vbv_compliance.f_buffer_size;
WORD32 i4_cbp_removal_delay_diff = 1;
if((ps_rc_ctxt->s_vbv_compliance.u4_prev_cpb_removal_delay_minus1 > 0) &&
(u4_cur_cpb_removal_delay_minus1 >
ps_rc_ctxt->s_vbv_compliance.u4_prev_cpb_removal_delay_minus1))
i4_cbp_removal_delay_diff =
(u4_cur_cpb_removal_delay_minus1 -
ps_rc_ctxt->s_vbv_compliance.u4_prev_cpb_removal_delay_minus1);
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level =
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level - (float)i4_bits_generated +
(i4_cbp_removal_delay_diff * ps_rc_ctxt->s_vbv_compliance.f_drain_rate);
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level_unclip =
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level;
if(ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level < 0)
{
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level = 0;
}
if(ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level >
ps_rc_ctxt->s_vbv_compliance.f_buffer_size)
{
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level =
ps_rc_ctxt->s_vbv_compliance.f_buffer_size;
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level_unclip -=
ps_rc_ctxt->s_vbv_compliance.f_buffer_size;
}
else if(ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level_unclip > 0)
{
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level_unclip = 0;
}
if(ps_rc_ctxt->e_rate_control_type == VBR_STREAMING)
{
if(ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level_unclip > 0)
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level_unclip = 0;
}
ps_rc_ctxt->s_vbv_compliance.u4_prev_cpb_removal_delay_minus1 = u4_cur_cpb_removal_delay_minus1;
}
/*!
******************************************************************************
* \if Function name : ihevce_vbv_complaince_init_level
*
* \brief
* this function initializes the hrd buffer level to be used for vbv compliance testing using the parameters feeded in VUI parameters
*
* \param[in] *pv_ctxt -> rc context
* *ps_vui -> VUI parameters
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
void ihevce_vbv_complaince_init_level(void *pv_ctxt, vui_t *ps_vui)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
ps_rc_ctxt->s_vbv_compliance.f_frame_rate =
(float)((float)ps_vui->u4_vui_time_scale / ps_vui->u4_vui_num_units_in_tick); //rc_get_frame_rate(ps_rc_ctxt->rc_hdl);
if(1 == ps_vui->s_vui_hrd_parameters.u1_sub_pic_cpb_params_present_flag)
{
ASSERT(1 == ps_vui->s_vui_hrd_parameters.u1_sub_pic_cpb_params_present_flag);
ps_rc_ctxt->s_vbv_compliance.f_bit_rate = (float)((
(ps_vui->s_vui_hrd_parameters.as_sub_layer_hrd_params[0].au4_bit_rate_du_value_minus1[0] +
1)
<< (6 + ps_vui->s_vui_hrd_parameters
.u4_bit_rate_scale))); //rc_get_bit_rate(ps_rc_ctxt->rc_hdl);
ps_rc_ctxt->s_vbv_compliance.f_buffer_size = (float)((
(ps_vui->s_vui_hrd_parameters.as_sub_layer_hrd_params[0].au4_cpb_size_du_value_minus1[0] +
1)
<< (4 + ps_vui->s_vui_hrd_parameters
.u4_cpb_size_du_scale))); //ps_rc_ctxt->u4_max_vbv_buff_size;
}
else
{
ps_rc_ctxt->s_vbv_compliance.f_bit_rate = (float)((
(ps_vui->s_vui_hrd_parameters.as_sub_layer_hrd_params[0].au4_bit_rate_value_minus1[0] +
1)
<< (6 + ps_vui->s_vui_hrd_parameters
.u4_bit_rate_scale))); //rc_get_bit_rate(ps_rc_ctxt->rc_hdl);
ps_rc_ctxt->s_vbv_compliance.f_buffer_size = (float)((
(ps_vui->s_vui_hrd_parameters.as_sub_layer_hrd_params[0].au4_cpb_size_value_minus1[0] +
1)
<< (4 + ps_vui->s_vui_hrd_parameters
.u4_cpb_size_scale))); //ps_rc_ctxt->u4_max_vbv_buff_size;
}
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level =
(float)ps_rc_ctxt->s_vbv_compliance.f_buffer_size; //ps_rc_ctxt->u4_max_vbv_buff_size;
ps_rc_ctxt->s_vbv_compliance.f_drain_rate =
((ps_rc_ctxt->s_vbv_compliance.f_bit_rate) / ps_rc_ctxt->s_vbv_compliance.f_frame_rate);
ps_rc_ctxt->s_vbv_compliance.u4_prev_cpb_removal_delay_minus1 = 0;
}
/*########################################################*/
/******* END OF VBV COMPLIANCE FUNCTIONS *****************/
/*#######################################################*/
/*################################################################*/
/******* START OF DYN CHANGE iN BITRATE FUNCTIONS *****************/
/*################################################################*/
/*!
******************************************************************************
* \if Function name : change_bitrate_vbv_complaince
*
* \brief
* this function updates the new bitrate and re calculates the drain rate
*
* \param[in] *pv_ctxt -> rc context
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
void change_bitrate_vbv_complaince(void *pv_ctxt, LWORD64 i8_new_bitrate, LWORD64 i8_buffer_size)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
ps_rc_ctxt->s_vbv_compliance.f_buffer_size = (float)i8_buffer_size;
ps_rc_ctxt->s_vbv_compliance.f_bit_rate = (float)i8_new_bitrate;
if(ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level > i8_buffer_size)
ps_rc_ctxt->s_vbv_compliance.f_curr_buffer_level = (float)i8_buffer_size;
ps_rc_ctxt->s_vbv_compliance.f_drain_rate =
ps_rc_ctxt->s_vbv_compliance.f_bit_rate / ps_rc_ctxt->s_vbv_compliance.f_frame_rate;
}
/*!
******************************************************************************
* \if Function name : ihevce_rc_register_dyn_change_bitrate
*
* \brief
* this function registers call to change bitrate dynamically.
*
* \param[in] *pv_ctxt -> rc context
*
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
void ihevce_rc_register_dyn_change_bitrate(
void *pv_ctxt, LWORD64 i8_new_bitrate, LWORD64 i8_new_peak_bitrate)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
ps_rc_ctxt->i8_new_bitrate = i8_new_bitrate;
ps_rc_ctxt->i8_new_peak_bitrate = i8_new_peak_bitrate;
ps_rc_ctxt->i4_bitrate_changed = 1;
ASSERT(ps_rc_ctxt->i8_new_bitrate > 0);
ASSERT(ps_rc_ctxt->i8_new_peak_bitrate > 0);
}
/*!
******************************************************************************
* \if Function name : ihevce_rc_get_new_bitrate
*
* \brief
* get new bitrate
*
* \param[in] *pv_ctxt -> rc context
*
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
LWORD64 ihevce_rc_get_new_bitrate(void *pv_ctxt)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
return ps_rc_ctxt->i8_new_bitrate;
}
/*!
******************************************************************************
* \if Function name : ihevce_rc_get_new_peak_bitrate
*
* \brief
* get new peak rate
*
* \param[in] *pv_ctxt -> rc context
*
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
LWORD64 ihevce_rc_get_new_peak_bitrate(void *pv_ctxt)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
return ps_rc_ctxt->i8_new_peak_bitrate;
}
/*!
******************************************************************************
* \if Function name : ihevce_rc_change_avg_bitrate
*
* \brief
* change average bitrate configured based on new bitrate
*
* \param[in] *pv_ctxt -> rc context
*
* \return
*
* \author
* Ittiam
*
*****************************************************************************
*/
LWORD64 ihevce_rc_change_avg_bitrate(void *pv_ctxt)
{
rc_context_t *ps_rc_ctxt = (rc_context_t *)pv_ctxt;
LWORD64 vbv_buffer_level_b4_change;
ASSERT(ps_rc_ctxt->i8_new_bitrate != -1);
ASSERT(ps_rc_ctxt->i8_new_peak_bitrate != -1);
/*Get the VBV buffer level just before forcing bitrate change*/
vbv_buffer_level_b4_change = (LWORD64)rc_get_ebf(ps_rc_ctxt->rc_hdl);
change_avg_bit_rate(
ps_rc_ctxt->rc_hdl,
(UWORD32)ps_rc_ctxt->i8_new_bitrate,
(UWORD32)ps_rc_ctxt->i8_new_peak_bitrate);
/*Once the request is serviced set new bitrate to -1*/
ps_rc_ctxt->i8_new_bitrate = -1;
ps_rc_ctxt->i8_new_peak_bitrate = -1;
return vbv_buffer_level_b4_change;
}
/*##############################################################*/
/******* END OF DYN CHNAGE iN BITRATE FUNCTIONS *****************/
/*##############################################################*/