/****************************************************************************** * * Copyright (C) 2022 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 * isvce_sub_pic_rc.c * * @brief * Contains functions used in sub-pic RC * ******************************************************************************* */ #include #include #include #include #include "ih264_typedefs.h" #include "ih264_cavlc_tables.h" #include "ih264_platform_macros.h" #include "ithread.h" #include "isvc_defs.h" #include "isvc_structs.h" #include "isvce_structs.h" #include "isvce_defs.h" #include "isvce_sub_pic_rc.h" #include "isvce_sub_pic_rc_private_defs.h" /* Dependencies of 'irc_picture_type.h' */ #include "irc_mem_req_and_acq.h" /* Dependencies of 'irc_rate_control_api_structs' */ #include "irc_picture_type.h" #include "irc_rd_model.h" #include "irc_vbr_storage_vbv.h" #include "irc_est_sad.h" #include "irc_bit_allocation.h" #include "irc_mb_model_based.h" #include "irc_cbr_buffer_control.h" #include "irc_vbr_str_prms.h" #include "irc_common.h" #include "irc_rate_control_api_structs.h" #include "irc_rate_control_api.h" /** ******************************************************************************* * * @brief * Returns size of buffers for storing subPicRC ctxt * * @returns Size of buffers * ******************************************************************************* */ UWORD32 isvce_get_sub_pic_rc_ctxt_size(UWORD8 u1_num_spatial_layers, DOUBLE d_spatial_res_ratio, UWORD32 u4_wd, UWORD32 u4_ht) { WORD32 i; UWORD32 u4_size = MAX_PROCESS_CTXT * sizeof(svc_sub_pic_rc_ctxt_t); u4_size += sizeof(sub_pic_rc_state_t); u4_size += ithread_get_mutex_struct_size(); for(i = u1_num_spatial_layers - 1; i >= 0; i--) { WORD32 i4_layer_wd = (WORD32) ((DOUBLE) u4_wd / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; WORD32 i4_layer_ht = ((DOUBLE) u4_ht / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; WORD32 i4_layer_mbs = (i4_layer_wd / MB_SIZE) * (i4_layer_ht / MB_SIZE); /* ps_mb_bits_info */ u4_size += i4_layer_mbs * sizeof(mb_bits_info_t); #if DUMP_SUB_PIC_RC_DATA /* ps_mb_bits_actual */ u4_size += i4_layer_mbs * sizeof(mb_bits_info_t); #endif } return u4_size; } void isvce_sub_pic_rc_ctxt_init(isvce_codec_t *ps_codec, iv_mem_rec_t *ps_mem_rec) { sub_pic_rc_state_t *ps_sub_pic_rc_state; WORD32 i, j; DOUBLE d_spatial_res_ratio = ps_codec->s_cfg.s_svc_params.d_spatial_res_ratio; UWORD8 u1_num_spatial_layers = ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers; UWORD32 u4_wd = ps_codec->s_cfg.u4_wd; UWORD32 u4_ht = ps_codec->s_cfg.u4_ht; UWORD8 *pu1_buf = ps_mem_rec->pv_base; WORD64 i8_alloc_mem_size = isvce_get_sub_pic_rc_ctxt_size(u1_num_spatial_layers, d_spatial_res_ratio, u4_wd, u4_ht); for(i = 0; i < MAX_PROCESS_CTXT; i++) { svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt = ps_codec->as_process[i].ps_sub_pic_rc_ctxt = (svc_sub_pic_rc_ctxt_t *) pu1_buf; pu1_buf += sizeof(ps_sub_pic_rc_ctxt[0]); i8_alloc_mem_size -= sizeof(ps_sub_pic_rc_ctxt[0]); if(0 == i) { ps_sub_pic_rc_ctxt->s_sub_pic_rc_constants.pv_state = ps_sub_pic_rc_state = (sub_pic_rc_state_t *) pu1_buf; pu1_buf += sizeof(ps_sub_pic_rc_state[0]); i8_alloc_mem_size -= sizeof(ps_sub_pic_rc_state[0]); ASSERT(i8_alloc_mem_size >= 0); ASSERT(NULL != ps_codec->s_rate_control.apps_rate_control_api); ASSERT(NULL != ps_codec->as_process->s_me_ctxt.pu1_mv_bits); ps_sub_pic_rc_state->s_svc_params = ps_codec->s_cfg.s_svc_params; ps_sub_pic_rc_state->pu1_uev_codeword_to_bits_map = gau1_uev_codeword_to_bits_map; ps_sub_pic_rc_state->pu1_sev_codeword_to_bits_map = ps_codec->as_process->s_me_ctxt.pu1_mv_bits; ps_sub_pic_rc_state->e_rc_mode = ps_codec->s_cfg.e_rc_mode; ps_sub_pic_rc_state->pv_bits_accumulator_mutex = (void *) pu1_buf; pu1_buf += ithread_get_mutex_struct_size(); i8_alloc_mem_size -= ithread_get_mutex_struct_size(); ithread_mutex_init(ps_sub_pic_rc_state->pv_bits_accumulator_mutex); for(j = u1_num_spatial_layers - 1; j >= 0; j--) { sub_pic_rc_layer_state_t *ps_layer_state = &ps_sub_pic_rc_state->as_sub_pic_rc_layer_states[j]; WORD32 i4_layer_wd = (WORD32) ((DOUBLE) u4_wd / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - j)) + 0.99; WORD32 i4_layer_ht = ((DOUBLE) u4_ht / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - j)) + 0.99; WORD32 i4_layer_mbs = (i4_layer_wd / MB_SIZE) * (i4_layer_ht / MB_SIZE); ps_layer_state->i4_wd = i4_layer_wd; ps_layer_state->i4_ht = i4_layer_ht; ps_layer_state->i4_num_mbs = i4_layer_mbs; ps_layer_state->pv_layer_rc_ctxt = ps_codec->s_rate_control.apps_rate_control_api[j]; ps_layer_state->ps_mb_bits_info = (mb_bits_info_t *) pu1_buf; pu1_buf += i4_layer_mbs * sizeof(ps_layer_state->ps_mb_bits_info[0]); i8_alloc_mem_size -= i4_layer_mbs * sizeof(ps_layer_state->ps_mb_bits_info[0]); ASSERT(i8_alloc_mem_size >= 0); #if DUMP_SUB_PIC_RC_DATA ps_layer_state->ps_mb_bits_actual = (mb_bits_info_t *) pu1_buf; pu1_buf += i4_layer_mbs * sizeof(ps_layer_state->ps_mb_bits_actual[0]); i8_alloc_mem_size -= i4_layer_mbs * sizeof(ps_layer_state->ps_mb_bits_actual[0]); ASSERT(i8_alloc_mem_size >= 0); { UWORD8 au1_file_path[MAX_SUB_PIC_RC_DUMP_FILE_PATH_LENGTH + 1]; sprintf((WORD8 *) au1_file_path, "%ssubPicRC%1d.txt", SUB_PIC_RC_DUMP_FILE_PATH, j); ps_layer_state->ps_data_dump_file = fopen(au1_file_path, "w"); ASSERT(NULL != ps_layer_state->ps_data_dump_file); } #endif } } else { svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt_src = ps_codec->as_process[0].ps_sub_pic_rc_ctxt; svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt_dst = ps_codec->as_process[i].ps_sub_pic_rc_ctxt; sub_pic_rc_state_t *ps_proc0_state = (sub_pic_rc_state_t *) ps_sub_pic_rc_ctxt_src->s_sub_pic_rc_constants.pv_state; ps_sub_pic_rc_ctxt_dst->s_sub_pic_rc_constants.pv_state = ps_proc0_state; } } } static FORCEINLINE void isvce_sub_pic_rc_qp_params_init(sub_pic_rc_qp_params_t *ps_qp_params, UWORD8 u1_min_qp, UWORD8 u1_max_qp) { ps_qp_params->u1_min_qp = u1_min_qp; ps_qp_params->u1_max_qp = u1_max_qp; ps_qp_params->pu4_qp_to_qscale_map = gau4_qp_to_qscale_map; ps_qp_params->pu1_qscale_to_qp_map = gau1_qscale_to_qp_map; } void isvce_sub_pic_rc_ctxt_layer_init(svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt) { sub_pic_rc_layer_state_t *ps_layer_state; svc_sub_pic_rc_constants_t *ps_sub_pic_rc_constants = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_constants; svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_variables; sub_pic_rc_state_t *ps_sub_pic_rc_state = (sub_pic_rc_state_t *) ps_sub_pic_rc_constants->pv_state; UWORD8 u1_spatial_layer_id = ps_sub_pic_rc_variables->s_layer_variables.u1_spatial_layer_id; ps_layer_state = &ps_sub_pic_rc_state->as_sub_pic_rc_layer_states[u1_spatial_layer_id]; memset(&ps_layer_state->s_cumulative_mb_bits, 0, sizeof(ps_layer_state->s_cumulative_mb_bits)); ps_layer_state->u4_num_mbs_sampled = 0; /* Frames with frameNum=0 are usually IDR's. RC model will be reset for IDR's. */ /* Hence, using VBVBufSize as a proxy for estimated bits */ if(0 == ps_sub_pic_rc_variables->s_layer_variables.i4_frame_num) { ps_layer_state->u4_allocated_bits = irc_get_vbv_buf_size(ps_layer_state->pv_layer_rc_ctxt) / 10.; } else { ps_layer_state->u4_allocated_bits = irc_get_prev_frm_est_bits(ps_layer_state->pv_layer_rc_ctxt); } isvce_sub_pic_rc_qp_params_init(&ps_layer_state->s_qp_params, ps_sub_pic_rc_variables->s_layer_variables.u1_min_qp, ps_sub_pic_rc_variables->s_layer_variables.u1_max_qp); } static FORCEINLINE UWORD32 isvce_sub_pic_rc_get_res_pred_flag_bits( svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables, sub_pic_rc_state_t *ps_sub_pic_rc_state) { isvce_mb_info_t *ps_mb_info = ps_sub_pic_rc_variables->s_mb_variables.ps_mb_info; UNUSED(ps_sub_pic_rc_state); return (ENABLE_RESIDUAL_PREDICTION && !ps_mb_info->u1_is_intra); } static FORCEINLINE UWORD32 isvce_sub_pic_rc_get_cbp_bits( svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables, sub_pic_rc_state_t *ps_sub_pic_rc_state) { isvce_mb_info_t *ps_mb_info = ps_sub_pic_rc_variables->s_mb_variables.ps_mb_info; UWORD32 u4_cbp = ps_sub_pic_rc_variables->s_mb_variables.u4_cbp; bool b_use_inter_cbp_map = !ps_mb_info->u1_is_intra || ps_mb_info->u1_base_mode_flag; return ps_sub_pic_rc_state ->pu1_uev_codeword_to_bits_map[gu1_cbp_map_tables[u4_cbp][b_use_inter_cbp_map]]; } static FORCEINLINE UWORD32 isvce_sub_pic_rc_get_mb_type_bits( svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables, sub_pic_rc_state_t *ps_sub_pic_rc_state) { UWORD32 u4_mb_type; isvce_mb_info_t *ps_mb_info = ps_sub_pic_rc_variables->s_mb_variables.ps_mb_info; UWORD32 u4_cbp = ps_sub_pic_rc_variables->s_mb_variables.u4_cbp; UWORD32 au4_cbps[NUM_SP_COMPONENTS] = {u4_cbp & 15, u4_cbp >> 4}; switch(ps_mb_info->u2_mb_type) { case I16x16: { u4_mb_type = ps_mb_info->s_intra_pu.s_i16x16_mode_data.u1_mode + 1 + (au4_cbps[UV] << 2) + (au4_cbps[Y] == 15) * 12; break; } case I4x4: { u4_mb_type = 5 * (ps_sub_pic_rc_variables->s_layer_variables.i4_slice_type != ISLICE); break; } case P16x16: { u4_mb_type = 0; break; } default: { return 0; } } return ps_sub_pic_rc_state->pu1_uev_codeword_to_bits_map[u4_mb_type]; } static FORCEINLINE UWORD32 isvce_sub_pic_rc_get_mb_pred_bits( svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables, sub_pic_rc_state_t *ps_sub_pic_rc_state) { WORD32 i; isvce_mb_info_t *ps_mb_info = ps_sub_pic_rc_variables->s_mb_variables.ps_mb_info; UWORD32 u4_bits = 0; switch(ps_mb_info->u2_mb_type) { case I16x16: { /* intra_chroma_pred_mode */ u4_bits += ps_sub_pic_rc_state ->pu1_uev_codeword_to_bits_map[ps_mb_info->s_intra_pu.u1_chroma_intra_mode]; break; } case I4x4: { intra4x4_mode_data_t *ps_i4x4_mode_data = ps_mb_info->s_intra_pu.as_i4x4_mode_data; for(i = 0; i < MAX_TU_IN_MB; i++) { /* prev_intra4x4_pred_mode_flag */ u4_bits += 1; /* rem_intra4x4_pred_mode */ u4_bits += 3 * (ps_i4x4_mode_data[i].u1_mode != ps_i4x4_mode_data[i].u1_predicted_mode); } /* intra_chroma_pred_mode */ u4_bits += ps_sub_pic_rc_state ->pu1_uev_codeword_to_bits_map[ps_mb_info->s_intra_pu.u1_chroma_intra_mode]; break; } case P16x16: { mv_t s_mvd; /* motion_prediction_flag_l0 */ u4_bits += USE_ILP_MV_AS_MVP; /* ref_idx_l0 */ if(2 == ps_sub_pic_rc_variables->s_layer_variables.i4_max_num_reference_frames) { u4_bits += 1; } else if(2 < ps_sub_pic_rc_variables->s_layer_variables.i4_max_num_reference_frames) { u4_bits += ps_sub_pic_rc_state->pu1_uev_codeword_to_bits_map [ps_mb_info->as_pu->as_me_info[L0].i1_ref_idx]; } /* mvd_l0 */ s_mvd.i2_mvx = ps_mb_info->as_pu->as_me_info[L0].s_mv.i2_mvx - ps_sub_pic_rc_variables->s_mb_variables .aps_mvps[ps_mb_info->as_pu->au1_mvp_idx[L0]] ->s_mv.i2_mvx; s_mvd.i2_mvy = ps_mb_info->as_pu->as_me_info[L0].s_mv.i2_mvy - ps_sub_pic_rc_variables->s_mb_variables .aps_mvps[ps_mb_info->as_pu->au1_mvp_idx[L0]] ->s_mv.i2_mvy; u4_bits += ps_sub_pic_rc_state->pu1_sev_codeword_to_bits_map[s_mvd.i2_mvx]; u4_bits += ps_sub_pic_rc_state->pu1_sev_codeword_to_bits_map[s_mvd.i2_mvy]; break; } default: { break; } } return u4_bits; } static void ihevce_svc_sub_pic_rc_set_header_bits(svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt) { sub_pic_rc_layer_state_t *ps_layer_state; mb_bits_info_t *ps_mb_bits_info; UWORD32 u4_mb_idx; svc_sub_pic_rc_constants_t *ps_sub_pic_rc_constants = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_constants; svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_variables; sub_pic_rc_state_t *ps_sub_pic_rc_state = (sub_pic_rc_state_t *) ps_sub_pic_rc_constants->pv_state; isvce_mb_info_t *ps_mb_info = ps_sub_pic_rc_variables->s_mb_variables.ps_mb_info; UWORD8 u1_spatial_layer_id = ps_sub_pic_rc_variables->s_layer_variables.u1_spatial_layer_id; ps_layer_state = &ps_sub_pic_rc_state->as_sub_pic_rc_layer_states[u1_spatial_layer_id]; u4_mb_idx = ps_sub_pic_rc_variables->s_mb_variables.s_mb_pos.i4_abscissa + ps_sub_pic_rc_variables->s_mb_variables.s_mb_pos.i4_ordinate * (ps_layer_state->i4_wd / MB_SIZE); ps_mb_bits_info = &ps_layer_state->ps_mb_bits_info[u4_mb_idx]; /* Hypotheses used for header bits estimation - */ /* 1. mb_skip_run, base_mode_flag, mb_type, mb_pred, residual_prediction_flag, * and cbp */ /* are considered as contibuting to header bits. */ /* 2. mb_skip_run = 1 bit */ /* 3. base_mode_flag = 1 bit */ /* 4. mb_type = LUT mapping mbType to corresponding ue(v) */ /* 5. mb_pred.I4x4 = 1 bit for 16 'prev_intra4x4_pred_mode_flag'; */ /* 3 bits for each explicitly signaled * 'rem_intra4x4_pred_mode' */ /* 6. mb_pred.Inter = 1 bit for 'motion_prediction_flag_l0' and * 'motion_prediction_flag_l1', when necessary; */ /* mvbits LUT for 'mvd_l0' and 'mvd_l1' */ /* 7. mb_pred.intra_chroma_pred_mode = LUT mapping intra_chroma_pred_mode to * corresponding ue(v) */ /* 8. residual_prediction_flag = 1 bit */ /* 9. coded_block_pattern = LUT mapping mbType to corresponding me(v) */ /* mb_skip_run is assumed to be either 0 or 1 */ ps_mb_bits_info->i8_header_bits += 1; /* 'base_mode_flag' */ if((ENABLE_ILP_MV || ENABLE_IBL_MODE) && u1_spatial_layer_id) { ps_mb_bits_info->i8_header_bits += 1; if(ps_mb_info->u1_base_mode_flag) { /* 'residual_prediction_flag' */ ps_mb_bits_info->i8_header_bits += isvce_sub_pic_rc_get_res_pred_flag_bits( ps_sub_pic_rc_variables, ps_sub_pic_rc_state); /* 'coded_block_pattern' */ ps_mb_bits_info->i8_header_bits += isvce_sub_pic_rc_get_cbp_bits(ps_sub_pic_rc_variables, ps_sub_pic_rc_state); return; } } /* 'mb_type' */ ps_mb_bits_info->i8_header_bits += isvce_sub_pic_rc_get_mb_type_bits(ps_sub_pic_rc_variables, ps_sub_pic_rc_state); if(PSKIP == ps_mb_info->u2_mb_type) { return; } /* 'mb_pred' */ ps_mb_bits_info->i8_header_bits += isvce_sub_pic_rc_get_mb_pred_bits(ps_sub_pic_rc_variables, ps_sub_pic_rc_state); /* 'residual_prediction_flag' */ ps_mb_bits_info->i8_header_bits += isvce_sub_pic_rc_get_res_pred_flag_bits(ps_sub_pic_rc_variables, ps_sub_pic_rc_state); } static FORCEINLINE UWORD32 isvce_sub_pic_rc_get_tu_residual_bits( svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables, WORD32 i4_coeff_start_idx, UWORD8 u1_num_coded_coeffs, UWORD8 u1_num_coeffs, bool b_is_chroma) { WORD32 i; UWORD32 u4_num_bits; UWORD32 u4_bits = 0; WORD16 *pi2_coeff = ((WORD16 *) ps_sub_pic_rc_variables->s_mb_variables.as_quant_coeffs[b_is_chroma ? UV : Y] .pv_data) + i4_coeff_start_idx; if(0 == u1_num_coded_coeffs) { return 0; } GETRANGE(u4_num_bits, u1_num_coded_coeffs); u4_bits += u4_num_bits; for(i = 0; i < u1_num_coeffs; i++) { if(pi2_coeff[i]) { GETRANGE(u4_num_bits, pi2_coeff[i]); u4_bits += u4_num_bits; } } return u4_bits; } static void ihevce_svc_sub_pic_rc_set_texture_bits(svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt) { sub_pic_rc_layer_state_t *ps_layer_state; mb_bits_info_t *ps_mb_bits_info; UWORD32 u4_mb_idx; WORD32 i, j; svc_sub_pic_rc_constants_t *ps_sub_pic_rc_constants = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_constants; svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_variables; sub_pic_rc_state_t *ps_sub_pic_rc_state = (sub_pic_rc_state_t *) ps_sub_pic_rc_constants->pv_state; isvce_mb_info_t *ps_mb_info = ps_sub_pic_rc_variables->s_mb_variables.ps_mb_info; UWORD8 u1_spatial_layer_id = ps_sub_pic_rc_variables->s_layer_variables.u1_spatial_layer_id; UWORD32 au4_cbps[NUM_SP_COMPONENTS] = {ps_sub_pic_rc_variables->s_mb_variables.u4_cbp & 15, ps_sub_pic_rc_variables->s_mb_variables.u4_cbp >> 4}; if(0 == ps_sub_pic_rc_variables->s_mb_variables.u4_cbp) { return; } if(MIN_TU_SIZE != ps_mb_info->u1_tx_size) { return; } ps_layer_state = &ps_sub_pic_rc_state->as_sub_pic_rc_layer_states[u1_spatial_layer_id]; u4_mb_idx = ps_sub_pic_rc_variables->s_mb_variables.s_mb_pos.i4_abscissa + ps_sub_pic_rc_variables->s_mb_variables.s_mb_pos.i4_ordinate * (ps_layer_state->i4_wd / MB_SIZE); ps_mb_bits_info = &ps_layer_state->ps_mb_bits_info[u4_mb_idx]; /* Hypotheses used for texture bits estimation - */ /* 1. Only level information is considered. */ /* 2. nnz is used as a proxy for coeff_token. */ /* 3. Both of the above are assumed coded via i(n). */ if(au4_cbps[Y]) { /* Y - DC */ if(I16x16 == ps_mb_info->u2_mb_type) { ps_mb_bits_info->i8_texture_bits += isvce_sub_pic_rc_get_tu_residual_bits( ps_sub_pic_rc_variables, 0, ps_sub_pic_rc_variables->s_mb_variables.apu1_nnzs[Y][0], NUM_COEFFS_IN_MIN_TU, false); } for(i = 0; i < MIN_TU_IN_MB; i++) { if(au4_cbps[Y] & (1 << i)) { UWORD32 u4_csbp = (ps_mb_info->u4_csbp >> (4 * i)) & 15; for(j = 0; j < NUM_4x4_IN_8x8; j++) { if(u4_csbp & (1 << j)) { /* 1 added to account for DC TU */ UWORD8 u1_blk_id = 1 + gau4_tu_zscan_id_to_rasterscan_id_map[i][j]; UWORD8 u1_nnz = ps_sub_pic_rc_variables->s_mb_variables.apu1_nnzs[Y][u1_blk_id]; if(u1_nnz && (I16x16 == ps_mb_info->u2_mb_type)) { u1_nnz -= !!(((WORD16 *) (ps_sub_pic_rc_variables->s_mb_variables .as_quant_coeffs[Y] .pv_data))[u1_blk_id - 1]); ps_mb_bits_info->i8_texture_bits += isvce_sub_pic_rc_get_tu_residual_bits( ps_sub_pic_rc_variables, u1_blk_id * ps_sub_pic_rc_variables->s_mb_variables .as_quant_coeffs[Y] .i4_data_stride + (I16x16 == ps_mb_info->u2_mb_type), u1_nnz, NUM_COEFFS_IN_MIN_TU - (I16x16 == ps_mb_info->u2_mb_type), false); } } } } } } if(au4_cbps[UV]) { for(i = ((WORD32) U); i <= ((WORD32) V); i++) { bool b_is_v = (i == ((WORD32) V)); ps_mb_bits_info->i8_texture_bits += isvce_sub_pic_rc_get_tu_residual_bits( ps_sub_pic_rc_variables, b_is_v * NUM_4x4_IN_8x8, ps_sub_pic_rc_variables->s_mb_variables .apu1_nnzs[UV][0 + b_is_v * (1 + NUM_4x4_IN_8x8)], NUM_4x4_IN_8x8, true); for(j = 0; j < NUM_4x4_IN_8x8; j++) { UWORD8 u1_nnz = ps_sub_pic_rc_variables->s_mb_variables .apu1_nnzs[UV][j + b_is_v * (1 + NUM_4x4_IN_8x8) + 1]; if(u1_nnz) { u1_nnz -= !!(((WORD16 *) (ps_sub_pic_rc_variables->s_mb_variables.as_quant_coeffs[UV] .pv_data))[j + b_is_v * NUM_4x4_IN_8x8]); ps_mb_bits_info->i8_texture_bits += isvce_sub_pic_rc_get_tu_residual_bits( ps_sub_pic_rc_variables, (j + b_is_v * NUM_4x4_IN_8x8 + 1) * ps_sub_pic_rc_variables->s_mb_variables.as_quant_coeffs[UV] .i4_data_stride + 1, u1_nnz, NUM_COEFFS_IN_MIN_TU - 1, true); } } } } } void isvce_sub_pic_rc_ctxt_update(svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt) { sub_pic_rc_layer_state_t *ps_layer_state; mb_bits_info_t *ps_mb_bits_info; UWORD32 u4_mb_idx; svc_sub_pic_rc_constants_t *ps_sub_pic_rc_constants = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_constants; svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_variables; sub_pic_rc_state_t *ps_sub_pic_rc_state = (sub_pic_rc_state_t *) ps_sub_pic_rc_constants->pv_state; isvce_mb_info_t *ps_mb_info = ps_sub_pic_rc_variables->s_mb_variables.ps_mb_info; UWORD8 u1_spatial_layer_id = ps_sub_pic_rc_variables->s_layer_variables.u1_spatial_layer_id; bool b_is_skip_mb = (PSKIP == ps_mb_info->u2_mb_type) || (BSKIP == ps_mb_info->u2_mb_type); if(!ENABLE_IN_FRAME_RC || (IVE_RC_NONE == ps_sub_pic_rc_state->e_rc_mode)) { return; } ps_layer_state = &ps_sub_pic_rc_state->as_sub_pic_rc_layer_states[u1_spatial_layer_id]; u4_mb_idx = ps_sub_pic_rc_variables->s_mb_variables.s_mb_pos.i4_abscissa + ps_sub_pic_rc_variables->s_mb_variables.s_mb_pos.i4_ordinate * (ps_layer_state->i4_wd / MB_SIZE); ps_mb_bits_info = &ps_layer_state->ps_mb_bits_info[u4_mb_idx]; memset(ps_mb_bits_info, 0, sizeof(ps_mb_bits_info[0])); if(!b_is_skip_mb) { ihevce_svc_sub_pic_rc_set_header_bits(ps_sub_pic_rc_ctxt); ihevce_svc_sub_pic_rc_set_texture_bits(ps_sub_pic_rc_ctxt); } ithread_mutex_lock(ps_sub_pic_rc_state->pv_bits_accumulator_mutex); ps_layer_state->s_cumulative_mb_bits.i8_header_bits += ps_mb_bits_info->i8_header_bits; ps_layer_state->s_cumulative_mb_bits.i8_texture_bits += ps_mb_bits_info->i8_texture_bits; ps_layer_state->u4_num_mbs_sampled++; ithread_mutex_unlock(ps_sub_pic_rc_state->pv_bits_accumulator_mutex); } UWORD8 isvce_sub_pic_rc_get_mb_qp(svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt, UWORD8 u1_cur_mb_qp) { sub_pic_rc_layer_state_t *ps_layer_state; DOUBLE d_bit_consumption_ratio; UWORD32 u4_frame_qscale; UWORD8 u1_mb_qp; UWORD32 u4_num_mbs_sampled; WORD32 i4_cumulative_mb_bits; svc_sub_pic_rc_constants_t *ps_sub_pic_rc_constants = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_constants; svc_sub_pic_rc_variables_t *ps_sub_pic_rc_variables = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_variables; sub_pic_rc_state_t *ps_sub_pic_rc_state = (sub_pic_rc_state_t *) ps_sub_pic_rc_constants->pv_state; UWORD8 u1_spatial_layer_id = ps_sub_pic_rc_variables->s_layer_variables.u1_spatial_layer_id; UWORD8 u1_frame_qp = ps_sub_pic_rc_variables->s_layer_variables.u1_frame_qp; if(!ENABLE_IN_FRAME_RC || (IVE_RC_NONE == ps_sub_pic_rc_state->e_rc_mode)) { return u1_cur_mb_qp; } ps_layer_state = &ps_sub_pic_rc_state->as_sub_pic_rc_layer_states[u1_spatial_layer_id]; ithread_mutex_lock(ps_sub_pic_rc_state->pv_bits_accumulator_mutex); u4_num_mbs_sampled = ps_layer_state->u4_num_mbs_sampled; if(u4_num_mbs_sampled < ((UWORD32) ceil(MIN_SAMPLED_MB_RATIO * ((DOUBLE) ps_layer_state->i4_num_mbs)))) { ithread_mutex_unlock(ps_sub_pic_rc_state->pv_bits_accumulator_mutex); return u1_cur_mb_qp; } i4_cumulative_mb_bits = (WORD32) (ps_layer_state->s_cumulative_mb_bits.i8_header_bits + ps_layer_state->s_cumulative_mb_bits.i8_texture_bits); if((0 == ps_layer_state->u4_allocated_bits) || (0 == u4_num_mbs_sampled)) { d_bit_consumption_ratio = nextafter(BIT_RATIO_FOR_OVERCONSUMPTION, INFINITY); } else { d_bit_consumption_ratio = (((DOUBLE) i4_cumulative_mb_bits) * ((DOUBLE) ps_layer_state->i4_num_mbs)) / (((DOUBLE) ps_layer_state->u4_allocated_bits) * ((DOUBLE) u4_num_mbs_sampled)); } ithread_mutex_unlock(ps_sub_pic_rc_state->pv_bits_accumulator_mutex); if((d_bit_consumption_ratio > BIT_RATIO_FOR_OVERCONSUMPTION) || (d_bit_consumption_ratio < BIT_RATIO_FOR_UNDERCONSUMPTION)) { u4_frame_qscale = ps_layer_state->s_qp_params.pu4_qp_to_qscale_map[u1_frame_qp] * d_bit_consumption_ratio + 0.5; u4_frame_qscale = CLIP3(ps_layer_state->s_qp_params.pu4_qp_to_qscale_map[0], MAX_SVC_QSCALE, u4_frame_qscale); u1_mb_qp = ps_layer_state->s_qp_params.pu1_qscale_to_qp_map[u4_frame_qscale]; u1_mb_qp = CLIP3(ps_layer_state->s_qp_params.u1_min_qp, ps_layer_state->s_qp_params.u1_max_qp, u1_mb_qp); u1_mb_qp = CLIP3(MAX(MIN_H264_QP, ((WORD16) u1_cur_mb_qp) - MAX_MB_QP_DECREMENT), MIN(MAX_H264_QP, ((WORD16) u1_cur_mb_qp) + MAX_MB_QP_INCREMENT), ((WORD16) u1_mb_qp)); /* This ensures mb_qp_delta stays within the interval [-26, 25] */ u1_mb_qp = CLIP3(MAX(MIN_H264_QP, ((WORD16) u1_frame_qp) - MAX_FRAME_QP_DECREMENT), MIN(MAX_H264_QP, ((WORD16) u1_frame_qp) + MAX_FRAME_QP_INCREMENT), ((WORD16) u1_mb_qp)); } else { u1_mb_qp = u1_cur_mb_qp; } { vbv_buf_status_e e_vbv_buf_status; picture_type_e e_rc_pic_type; DOUBLE d_est_frame_bits; WORD32 i4_num_bits_to_prevent_vbv_underflow; d_est_frame_bits = ((DOUBLE) i4_cumulative_mb_bits) * ((DOUBLE) ps_layer_state->i4_num_mbs); d_est_frame_bits /= u4_num_mbs_sampled; switch(ps_sub_pic_rc_variables->s_layer_variables.i4_slice_type) { case ISLICE: { e_rc_pic_type = I_PIC; break; } case PSLICE: { e_rc_pic_type = P_PIC; break; } default: { e_rc_pic_type = B_PIC; break; } } e_vbv_buf_status = irc_get_buffer_status(ps_layer_state->pv_layer_rc_ctxt, (WORD32) d_est_frame_bits, e_rc_pic_type, &i4_num_bits_to_prevent_vbv_underflow); /* This models dec VBV buffer */ if(VBV_OVERFLOW == e_vbv_buf_status) { u1_mb_qp--; } else if(VBV_UNDERFLOW == e_vbv_buf_status) { u1_mb_qp++; } /* This ensures mb_qp_delta stays within the interval [-26, 25] */ u1_mb_qp = CLIP3(ps_layer_state->s_qp_params.u1_min_qp, ps_layer_state->s_qp_params.u1_max_qp, u1_mb_qp); u1_mb_qp = CLIP3(MAX(MIN_H264_QP, ((WORD16) u1_frame_qp) - MAX_FRAME_QP_DECREMENT), MIN(MAX_H264_QP, ((WORD16) u1_frame_qp) + MAX_FRAME_QP_INCREMENT), ((WORD16) u1_mb_qp)); } return u1_mb_qp; } void isvce_sub_pic_rc_get_entropy_data(svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt) { #if DUMP_SUB_PIC_RC_DATA sub_pic_rc_layer_state_t *ps_layer_state; UWORD32 u4_mb_idx; svc_sub_pic_rc_constants_t *ps_sub_pic_rc_constants = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_constants; svc_sub_pic_rc_entropy_variables_t *ps_sub_pic_rc_variables = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_entropy_variables; sub_pic_rc_state_t *ps_sub_pic_rc_state = (sub_pic_rc_state_t *) ps_sub_pic_rc_constants->pv_state; UWORD8 u1_spatial_layer_id = ps_sub_pic_rc_variables->u1_spatial_layer_id; if(!ENABLE_IN_FRAME_RC || (IVE_RC_NONE == ps_sub_pic_rc_state->e_rc_mode)) { return; } ps_layer_state = &ps_sub_pic_rc_state->as_sub_pic_rc_layer_states[u1_spatial_layer_id]; u4_mb_idx = ps_sub_pic_rc_variables->s_mb_pos.i4_abscissa + ps_sub_pic_rc_variables->s_mb_pos.i4_ordinate * (ps_layer_state->i4_wd / MB_SIZE); ps_layer_state->ps_mb_bits_actual[u4_mb_idx] = ps_sub_pic_rc_variables->s_mb_bits; #else UNUSED(ps_sub_pic_rc_ctxt); #endif } void isvce_sub_pic_rc_dump_data(svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt) { #if DUMP_SUB_PIC_RC_DATA WORD32 i, j, k; svc_sub_pic_rc_constants_t *ps_sub_pic_rc_constants = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_constants; sub_pic_rc_state_t *ps_sub_pic_rc_state = (sub_pic_rc_state_t *) ps_sub_pic_rc_constants->pv_state; if(!ENABLE_IN_FRAME_RC || (IVE_RC_NONE == ps_sub_pic_rc_state->e_rc_mode)) { return; } for(i = 0; i < ps_sub_pic_rc_state->s_svc_params.u1_num_spatial_layers; i++) { sub_pic_rc_layer_state_t *ps_layer_state = &ps_sub_pic_rc_state->as_sub_pic_rc_layer_states[i]; for(j = 0; j < (ps_layer_state->i4_ht / MB_SIZE); j++) { for(k = 0; k < (ps_layer_state->i4_wd / MB_SIZE); k++) { mb_bits_info_t *ps_mb_bits_est = &ps_layer_state->ps_mb_bits_info[k + j * (ps_layer_state->i4_wd / MB_SIZE)]; mb_bits_info_t *ps_mb_bits_actual = &ps_layer_state->ps_mb_bits_actual[k + j * (ps_layer_state->i4_wd / MB_SIZE)]; fprintf(ps_layer_state->ps_data_dump_file, "%ld,%ld,%ld,%ld,\n", ps_mb_bits_est->i8_header_bits, ps_mb_bits_est->i8_texture_bits, ps_mb_bits_actual->i8_header_bits, ps_mb_bits_actual->i8_texture_bits); } } } #else UNUSED(ps_sub_pic_rc_ctxt); #endif } void isvce_sub_pic_rc_ctxt_delete(svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt) { sub_pic_rc_state_t *ps_sub_pic_rc_state = (sub_pic_rc_state_t *) ps_sub_pic_rc_ctxt->s_sub_pic_rc_constants.pv_state; ithread_mutex_destroy(ps_sub_pic_rc_state->pv_bits_accumulator_mutex); #if DUMP_SUB_PIC_RC_DATA { WORD32 i; UWORD8 u1_num_spatial_layers = ps_sub_pic_rc_state->s_svc_params.u1_num_spatial_layers; for(i = u1_num_spatial_layers - 1; i >= 0; i--) { sub_pic_rc_layer_state_t *ps_layer_state = &ps_sub_pic_rc_state->as_sub_pic_rc_layer_states[i]; if(ps_layer_state->ps_data_dump_file) { fclose(ps_layer_state->ps_data_dump_file); } ps_layer_state->ps_data_dump_file = NULL; } } #endif }