| /****************************************************************************** |
| * |
| * 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_frame_process.c |
| * |
| * \brief |
| * This file contains top level functions related Frame processing |
| * |
| * \date |
| * 18/09/2012 |
| * |
| * \author |
| * Ittiam |
| * |
| * |
| * List of Functions |
| * |
| * |
| ****************************************************************************** |
| */ |
| |
| /*****************************************************************************/ |
| /* File Includes */ |
| /*****************************************************************************/ |
| /* System include files */ |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <assert.h> |
| #include <stdarg.h> |
| #include <math.h> |
| #include <time.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 "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 "ihevc_cabac_tables.h" |
| #include "ihevc_common_tables.h" |
| |
| #include "ihevce_defs.h" |
| #include "ihevce_buffer_que_interface.h" |
| #include "ihevce_hle_interface.h" |
| #include "ihevce_hle_q_func.h" |
| #include "ihevce_lap_enc_structs.h" |
| #include "ihevce_lap_interface.h" |
| #include "ihevce_multi_thrd_structs.h" |
| #include "ihevce_multi_thrd_funcs.h" |
| #include "ihevce_me_common_defs.h" |
| #include "ihevce_had_satd.h" |
| #include "ihevce_error_checks.h" |
| #include "ihevce_error_codes.h" |
| #include "ihevce_bitstream.h" |
| #include "ihevce_cabac.h" |
| #include "ihevce_rdoq_macros.h" |
| #include "ihevce_function_selector.h" |
| #include "ihevce_enc_structs.h" |
| #include "ihevce_global_tables.h" |
| #include "ihevce_cmn_utils_instr_set_router.h" |
| #include "ihevce_ipe_instr_set_router.h" |
| #include "ihevce_entropy_structs.h" |
| #include "ihevce_enc_loop_structs.h" |
| #include "ihevce_enc_loop_utils.h" |
| #include "ihevce_inter_pred.h" |
| #include "ihevce_common_utils.h" |
| #include "ihevce_sub_pic_rc.h" |
| #include "hme_datatype.h" |
| #include "hme_interface.h" |
| #include "hme_common_defs.h" |
| #include "hme_defs.h" |
| #include "ihevce_enc_loop_pass.h" |
| #include "ihevce_trace.h" |
| #include "ihevce_encode_header.h" |
| #include "ihevce_encode_header_sei_vui.h" |
| #include "ihevce_ipe_structs.h" |
| #include "ihevce_ipe_pass.h" |
| #include "ihevce_dep_mngr_interface.h" |
| #include "ihevce_rc_enc_structs.h" |
| #include "hme_globals.h" |
| #include "ihevce_me_pass.h" |
| #include "ihevce_coarse_me_pass.h" |
| #include "ihevce_frame_process.h" |
| #include "ihevce_rc_interface.h" |
| #include "ihevce_profile.h" |
| #include "ihevce_decomp_pre_intra_structs.h" |
| #include "ihevce_decomp_pre_intra_pass.h" |
| #include "ihevce_frame_process_utils.h" |
| |
| #include "cast_types.h" |
| #include "osal.h" |
| #include "osal_defaults.h" |
| |
| /*****************************************************************************/ |
| /* Constant Macros */ |
| /*****************************************************************************/ |
| |
| #define REF_MOD_STRENGTH 1.0 |
| #define REF_MAX_STRENGTH 1.4f |
| |
| /*****************************************************************************/ |
| /* Extern variables */ |
| /*****************************************************************************/ |
| |
| /** |
| * @var QP2QUANT_MD[] |
| * |
| * @brief Direct Cost Comoparision Table |
| * |
| * @param Comments: Direct cost is compared with 16 * QP2QUANT_MD[Qp] |
| * If direct cost is less than 16 * QP2QUANT_MD[Qp] |
| * than direct cost is assumed to be zero |
| */ |
| const WORD16 QP2QUANT_MD[52] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, |
| 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16, 18, 20, |
| 23, 25, 29, 32, 36, 40, 45, 51, 57, 64, 72, 81, 91 }; |
| |
| /* |
| Gaussian 11x11 window with a sigma of 1.5 - values multiplied by 2048 |
| Window made into 9x9 window as most entries were zero |
| The center weight has been reduced by 1 after dropping first row/col and last row/col |
| */ |
| UWORD8 g_u1_win_size = 9; |
| UWORD8 g_u1_win_q_shift = 11; |
| UWORD8 au1_g_win[81] = { 0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 3, 8, 16, 20, 16, 8, 3, |
| 1, 2, 8, 24, 48, 60, 48, 24, 8, 2, 3, 16, 48, 93, 116, 93, 48, |
| 16, 3, 4, 20, 60, 116, 144, 116, 60, 20, 4, 3, 16, 48, 93, 116, 93, |
| 48, 16, 3, 2, 8, 24, 48, 60, 48, 24, 8, 2, 1, 3, 8, 16, 20, |
| 16, 8, 3, 1, 0, 1, 2, 3, 4, 3, 2, 1, 0 }; |
| |
| /* lagrange params */ |
| const double lamda_modifier_for_I_pic[8] = { 0.85, 0.7471, 0.6646, 0.5913, |
| 0.5261, 0.4680, 0.4164, 0.3705 }; |
| |
| /*****************************************************************************/ |
| /* Function Definitions */ |
| /*****************************************************************************/ |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_mbr_quality_tool_set_configuration \endif |
| * |
| * \brief |
| * tool set selection for auxilary bitrate. currently only num intra and inter |
| * candidates for auxilary bitrates are controlled |
| * |
| * \param[in] ps_enc_loop_thrd_ctxt : enc ctxt |
| * \param[in] ps_stat_prms: static parameters |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_mbr_quality_tool_set_configuration( |
| ihevce_enc_loop_ctxt_t *ps_enc_loop_thrd_ctxt, ihevce_static_cfg_params_t *ps_stat_prms) |
| { |
| /* for single bitrate encoder*/ |
| switch(ps_stat_prms->s_tgt_lyr_prms.i4_mbr_quality_setting) |
| { |
| case IHEVCE_MBR_HIGH_QUALITY: |
| ps_enc_loop_thrd_ctxt->i4_num_modes_to_evaluate_intra = 3; |
| ps_enc_loop_thrd_ctxt->i4_num_modes_to_evaluate_inter = 4; |
| break; |
| |
| case IHEVCE_MBR_MEDIUM_SPEED: |
| ps_enc_loop_thrd_ctxt->i4_num_modes_to_evaluate_intra = 3; |
| ps_enc_loop_thrd_ctxt->i4_num_modes_to_evaluate_inter = 3; |
| break; |
| |
| case IHEVCE_MBR_HIGH_SPEED: |
| ps_enc_loop_thrd_ctxt->i4_num_modes_to_evaluate_intra = 2; |
| ps_enc_loop_thrd_ctxt->i4_num_modes_to_evaluate_inter = 2; |
| break; |
| |
| case IHEVCE_MBR_EXTREME_SPEED: |
| ps_enc_loop_thrd_ctxt->i4_num_modes_to_evaluate_intra = 1; |
| ps_enc_loop_thrd_ctxt->i4_num_modes_to_evaluate_inter = 1; |
| break; |
| |
| default: |
| assert(0); |
| break; |
| } |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_find_free_indx \endif |
| * |
| * \brief |
| * Pre encode Frame processing slave thread entry point function |
| * |
| * \param[in] Frame processing thread context pointer |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| WORD32 ihevce_find_free_indx(recon_pic_buf_t **pps_recon_buf_q, WORD32 i4_num_buf) |
| { |
| WORD32 i4_ctr; |
| WORD32 i4_is_full = 1; |
| WORD32 i4_least_POC = 0x7FFFFFFF; |
| WORD32 i4_least_POC_idx = -1; |
| WORD32 i4_least_GOP_num = 0x7FFFFFFF; |
| |
| for(i4_ctr = 0; i4_ctr < i4_num_buf; i4_ctr++) |
| { |
| if(pps_recon_buf_q[i4_ctr]->i4_is_free == 1) |
| { |
| i4_is_full = 0; |
| break; |
| } |
| } |
| if(i4_is_full) |
| { |
| /* remove if any non-reference pictures are present */ |
| for(i4_ctr = 0; i4_ctr < i4_num_buf; i4_ctr++) |
| { |
| if(!pps_recon_buf_q[i4_ctr]->i4_is_reference && |
| pps_recon_buf_q[i4_ctr]->i4_non_ref_free_flag) |
| { |
| i4_least_POC_idx = i4_ctr; |
| break; |
| } |
| } |
| /* if all non reference pictures are removed, then find the least poc |
| in the least gop number*/ |
| if(i4_least_POC_idx == -1) |
| { |
| for(i4_ctr = 0; i4_ctr < i4_num_buf; i4_ctr++) |
| { |
| if(i4_least_GOP_num > pps_recon_buf_q[i4_ctr]->i4_idr_gop_num) |
| { |
| i4_least_GOP_num = pps_recon_buf_q[i4_ctr]->i4_idr_gop_num; |
| } |
| } |
| for(i4_ctr = 0; i4_ctr < i4_num_buf; i4_ctr++) |
| { |
| if(i4_least_POC > pps_recon_buf_q[i4_ctr]->i4_poc && |
| i4_least_GOP_num == pps_recon_buf_q[i4_ctr]->i4_idr_gop_num) |
| { |
| i4_least_POC = pps_recon_buf_q[i4_ctr]->i4_poc; |
| i4_least_POC_idx = i4_ctr; |
| } |
| } |
| } |
| } |
| return i4_least_POC_idx; |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : complexity_RC_reset_marking \endif |
| * |
| * \brief |
| * this function the complexity variation and set the complexity change flag for |
| * rate control to reset the model |
| * |
| * \param[in] ps_enc_loop_thrd_ctxt : enc ctxt |
| * \param[in] ps_stat_prms: static parameters |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void complexity_RC_reset_marking(enc_ctxt_t *ps_enc_ctxt, WORD32 i4_cur_ipe_idx, WORD32 i4_end_flag) |
| { |
| rc_lap_out_params_t *ps_cur_ipe_lap_out; |
| rc_lap_out_params_t *ps_lap_out_temp; |
| WORD32 i4_max_temporal_layers; |
| |
| ps_cur_ipe_lap_out = |
| &ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_rc_lap_out; |
| ps_cur_ipe_lap_out->i4_is_cmplx_change_reset_model = 0; |
| ps_cur_ipe_lap_out->i4_is_cmplx_change_reset_bits = 0; |
| |
| i4_max_temporal_layers = ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_max_temporal_layers; |
| |
| /*reset the RC_reset counter at reset points*/ |
| if(ps_cur_ipe_lap_out->i4_is_I_only_scd || ps_cur_ipe_lap_out->i4_is_non_I_scd || |
| ps_cur_ipe_lap_out->i4_rc_scene_type == SCENE_TYPE_SCENE_CUT) |
| { |
| ps_enc_ctxt->i4_past_RC_reset_count = 0; |
| } |
| |
| if(ps_cur_ipe_lap_out->i4_rc_scene_type == SCENE_TYPE_SCENE_CUT) |
| { |
| ps_enc_ctxt->i4_past_RC_scd_reset_count = 0; |
| } |
| ps_enc_ctxt->i4_past_RC_reset_count++; |
| ps_enc_ctxt->i4_past_RC_scd_reset_count++; |
| |
| /*complexity based rate control reset */ |
| |
| if((ps_cur_ipe_lap_out->i4_rc_pic_type == IV_P_FRAME || |
| ps_cur_ipe_lap_out->i4_rc_pic_type == IV_I_FRAME) && |
| (i4_max_temporal_layers > 1) && (!i4_end_flag) && |
| (ps_enc_ctxt->s_multi_thrd.i4_delay_pre_me_btw_l0_ipe > (2 * (1 << i4_max_temporal_layers)))) |
| { |
| WORD32 i4_is_cur_pic_high_complex_region = |
| ps_enc_ctxt->s_multi_thrd.aps_curr_out_pre_enc[i4_cur_ipe_idx] |
| ->i4_is_high_complex_region; |
| WORD32 i4_next_ipe_idx; |
| WORD32 i4_next_next_ipe_idx; |
| WORD32 i4_temp_ipe_idx; |
| WORD32 i; |
| |
| ps_enc_ctxt->i4_future_RC_reset = 0; |
| ps_enc_ctxt->i4_future_RC_scd_reset = 0; |
| ASSERT(i4_is_cur_pic_high_complex_region != -1); |
| |
| /*get the next idx of p/i picture */ |
| i4_next_ipe_idx = |
| (i4_cur_ipe_idx + 1) % (ps_enc_ctxt->s_multi_thrd.i4_max_delay_pre_me_btw_l0_ipe + 1); |
| i4_temp_ipe_idx = |
| (i4_cur_ipe_idx + 1) % (ps_enc_ctxt->s_multi_thrd.i4_max_delay_pre_me_btw_l0_ipe + 1); |
| for(i = 0; i < (1 << i4_max_temporal_layers); i++) |
| { |
| ps_lap_out_temp = |
| &ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_next_ipe_idx]->s_rc_lap_out; |
| |
| if(ps_lap_out_temp->i4_rc_pic_type == IV_P_FRAME || |
| ps_lap_out_temp->i4_rc_pic_type == IV_I_FRAME) |
| { |
| break; |
| } |
| i4_next_ipe_idx = (i4_next_ipe_idx + 1) % |
| (ps_enc_ctxt->s_multi_thrd.i4_max_delay_pre_me_btw_l0_ipe + 1); |
| } |
| /* get the next idx of next p/i picture*/ |
| i4_next_next_ipe_idx = |
| (i4_next_ipe_idx + 1) % (ps_enc_ctxt->s_multi_thrd.i4_max_delay_pre_me_btw_l0_ipe + 1); |
| for(i = 0; i < (1 << i4_max_temporal_layers); i++) |
| { |
| ps_lap_out_temp = |
| &ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_next_next_ipe_idx]->s_rc_lap_out; |
| |
| if(ps_lap_out_temp->i4_rc_pic_type == IV_P_FRAME || |
| ps_lap_out_temp->i4_rc_pic_type == IV_I_FRAME) |
| { |
| break; |
| } |
| i4_next_next_ipe_idx = (i4_next_next_ipe_idx + 1) % |
| (ps_enc_ctxt->s_multi_thrd.i4_max_delay_pre_me_btw_l0_ipe + 1); |
| } |
| |
| /*check for any possible RC reset in the future 8 frames*/ |
| for(i = 0; i < 8; i++) |
| { |
| ps_lap_out_temp = |
| &ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_temp_ipe_idx]->s_rc_lap_out; |
| |
| if(ps_lap_out_temp->i4_is_I_only_scd || ps_lap_out_temp->i4_is_non_I_scd || |
| ps_lap_out_temp->i4_rc_scene_type == SCENE_TYPE_SCENE_CUT) |
| { |
| ps_enc_ctxt->i4_future_RC_reset = 1; |
| } |
| if(ps_cur_ipe_lap_out->i4_rc_scene_type == SCENE_TYPE_SCENE_CUT) |
| { |
| ps_enc_ctxt->i4_future_RC_scd_reset = 1; |
| } |
| i4_temp_ipe_idx = (i4_temp_ipe_idx + 1) % |
| (ps_enc_ctxt->s_multi_thrd.i4_max_delay_pre_me_btw_l0_ipe + 1); |
| } |
| |
| if((!ps_enc_ctxt->i4_future_RC_reset) && (ps_enc_ctxt->i4_past_RC_reset_count > 8)) |
| { |
| /*if the prev two P/I pic is not in high complex region |
| then enable reset RC flag*/ |
| if((!ps_enc_ctxt->ai4_is_past_pic_complex[0]) && |
| (!ps_enc_ctxt->ai4_is_past_pic_complex[1])) |
| { |
| if(i4_is_cur_pic_high_complex_region) |
| { |
| ps_cur_ipe_lap_out->i4_is_cmplx_change_reset_model = 1; |
| ps_cur_ipe_lap_out->i4_is_cmplx_change_reset_bits = 1; |
| ps_enc_ctxt->i4_is_I_reset_done = 0; |
| } |
| } |
| |
| /*if the next two P/I pic is not in high complex region |
| then enable reset RC flag*/ |
| if((!ps_enc_ctxt->s_multi_thrd.aps_curr_out_pre_enc[i4_next_ipe_idx] |
| ->i4_is_high_complex_region) && |
| (!ps_enc_ctxt->s_multi_thrd.aps_curr_out_pre_enc[i4_next_next_ipe_idx] |
| ->i4_is_high_complex_region)) |
| { |
| if(i4_is_cur_pic_high_complex_region) |
| { |
| ps_cur_ipe_lap_out->i4_is_cmplx_change_reset_model = 1; |
| ps_cur_ipe_lap_out->i4_is_cmplx_change_reset_bits = 1; |
| ps_enc_ctxt->i4_is_I_reset_done = 0; |
| } |
| } |
| } |
| else if((!ps_enc_ctxt->i4_future_RC_scd_reset) && (ps_enc_ctxt->i4_past_RC_scd_reset_count > 8)) |
| { |
| /*if the prev two P/I pic is not in high complex region |
| then enable reset RC flag*/ |
| if((!ps_enc_ctxt->ai4_is_past_pic_complex[0]) && |
| (!ps_enc_ctxt->ai4_is_past_pic_complex[1])) |
| { |
| if(i4_is_cur_pic_high_complex_region) |
| { |
| ps_cur_ipe_lap_out->i4_is_cmplx_change_reset_bits = 1; |
| } |
| } |
| |
| /*if the next two P/I pic is not in high complex region |
| then enable reset RC flag*/ |
| if((!ps_enc_ctxt->s_multi_thrd.aps_curr_out_pre_enc[i4_next_ipe_idx] |
| ->i4_is_high_complex_region) && |
| (!ps_enc_ctxt->s_multi_thrd.aps_curr_out_pre_enc[i4_next_next_ipe_idx] |
| ->i4_is_high_complex_region)) |
| { |
| if(i4_is_cur_pic_high_complex_region) |
| { |
| ps_cur_ipe_lap_out->i4_is_cmplx_change_reset_bits = 1; |
| } |
| } |
| } |
| |
| /* forcing I frame reset after complexity change is disable as it gives gain, could be due to that |
| required i reset is already happening on pre Intra SAD*/ |
| /*if(!ps_enc_ctxt->i4_is_I_reset_done && (ps_cur_ipe_lap_out->i4_pic_type |
| == IV_I_FRAME)) |
| { |
| ps_cur_ipe_lap_out->i4_is_I_only_scd = 1; |
| ps_enc_ctxt->i4_is_I_reset_done = 1; |
| }*/ |
| |
| ps_enc_ctxt->ai4_is_past_pic_complex[0] = i4_is_cur_pic_high_complex_region; |
| |
| ps_enc_ctxt->ai4_is_past_pic_complex[1] = ps_enc_ctxt->ai4_is_past_pic_complex[0]; |
| } |
| return; |
| } |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_manage_ref_pics \endif |
| * |
| * \brief |
| * Reference picture management based on delta poc array given by LAP |
| * Populates the reference list after removing non used reference pictures |
| * populates the delta poc of reference pics to be signalled in slice header |
| * |
| * \param[in] encoder context pointer |
| * \param[in] current LAP Encoder buffer pointer |
| * \param[in] current frame process and entropy buffer pointer |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_pre_enc_manage_ref_pics( |
| enc_ctxt_t *ps_enc_ctxt, |
| ihevce_lap_enc_buf_t *ps_curr_inp, |
| pre_enc_me_ctxt_t *ps_curr_out, |
| WORD32 i4_ping_pong) |
| { |
| /* local variables */ |
| WORD32 ctr; |
| WORD32 ref_pics; |
| WORD32 ai4_buf_status[HEVCE_MAX_DPB_PICS] = { 0 }; |
| WORD32 curr_poc; |
| WORD32 wp_flag = 0; |
| WORD32 num_ref_pics_list0 = 0; |
| WORD32 num_ref_pics_list1 = 0; |
| WORD32 cra_poc = ps_curr_inp->s_lap_out.i4_assoc_IRAP_poc; |
| WORD32 slice_type = ps_curr_out->s_slice_hdr.i1_slice_type; |
| recon_pic_buf_t *(*aps_pre_enc_ref_pic_list)[HEVCE_MAX_REF_PICS * 2]; |
| WORD32 i4_inc_L1_active_ref_pic = 0; |
| WORD32 i4_inc_L0_active_ref_pic = 0; |
| |
| (void)ps_curr_out; |
| curr_poc = ps_curr_inp->s_lap_out.i4_poc; |
| |
| /* Number of reference pics given by LAP should not be greater than max */ |
| ASSERT(HEVCE_MAX_REF_PICS >= ps_curr_inp->s_lap_out.i4_num_ref_pics); |
| |
| /*derive ref_pic_list based on ping_pong instance */ |
| aps_pre_enc_ref_pic_list = ps_enc_ctxt->aps_pre_enc_ref_lists[i4_ping_pong]; |
| |
| /* derive the weighted prediction enable flag based on slice type */ |
| if(BSLICE == slice_type) |
| { |
| wp_flag = ps_curr_inp->s_lap_out.i1_weighted_bipred_flag; |
| } |
| else if(PSLICE == slice_type) |
| { |
| wp_flag = ps_curr_inp->s_lap_out.i1_weighted_pred_flag; |
| } |
| else |
| { |
| wp_flag = 0; |
| } |
| |
| /*to support diplicate pics*/ |
| { |
| WORD32 i, j; |
| for(i = 0; i < 2; i++) |
| { |
| for(j = 0; j < HEVCE_MAX_REF_PICS * 2; j++) |
| { |
| aps_pre_enc_ref_pic_list[i][j] = |
| &ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][i][j]; |
| } |
| } |
| } |
| |
| /* run a loop over the number of reference pics given by LAP */ |
| for(ref_pics = 0; ref_pics < ps_curr_inp->s_lap_out.i4_num_ref_pics; ref_pics++) |
| { |
| WORD32 ref_poc; |
| WORD32 i4_loop = 1; |
| WORD32 i4_temp_list; |
| |
| ref_poc = curr_poc + ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_ref_pic_delta_poc; |
| |
| /* run a loop to check the poc based on delta poc array */ |
| for(ctr = 0; ctr < ps_enc_ctxt->i4_pre_enc_num_buf_recon_q; ctr++) |
| { |
| /* if the POC is matching with current ref picture*/ |
| if((ref_poc == ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr]->i4_poc) && |
| (0 == ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr]->i4_is_free)) |
| { |
| /* mark the buf status as used */ |
| ai4_buf_status[ctr] = 1; |
| |
| /* populate the reference lists based on delta poc array */ |
| if((ref_poc < curr_poc) || (0 == curr_poc)) |
| { |
| /* list 0 */ |
| memcpy( |
| &ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_0][num_ref_pics_list0], |
| ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr], |
| sizeof(recon_pic_buf_t)); |
| i4_temp_list = num_ref_pics_list0; |
| |
| /*duplicate pics added to the list*/ |
| while(i4_loop != ps_curr_inp->s_lap_out.as_ref_pics[ref_pics] |
| .i4_num_duplicate_entries_in_ref_list) |
| { |
| /* list 0 */ |
| i4_temp_list++; |
| memcpy( |
| &ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_0][i4_temp_list], |
| ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr], |
| sizeof(recon_pic_buf_t)); |
| i4_loop++; |
| } |
| |
| /* populate weights and offsets corresponding to this ref pic */ |
| memcpy( |
| &ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_0][num_ref_pics_list0] |
| .s_weight_offset, |
| &ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].as_wght_off[0], |
| sizeof(ihevce_wght_offst_t)); |
| |
| /* Store the used as ref for current pic flag */ |
| ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_0][num_ref_pics_list0] |
| .i4_used_by_cur_pic_flag = |
| ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_used_by_cur_pic_flag; |
| |
| num_ref_pics_list0++; |
| i4_loop = 1; |
| /*duplicate pics added to the list*/ |
| while(i4_loop != ps_curr_inp->s_lap_out.as_ref_pics[ref_pics] |
| .i4_num_duplicate_entries_in_ref_list) |
| { |
| /* populate weights and offsets corresponding to this ref pic */ |
| memcpy( |
| &ps_enc_ctxt |
| ->as_pre_enc_ref_lists[i4_ping_pong][LIST_0][num_ref_pics_list0] |
| .s_weight_offset, |
| &ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].as_wght_off[i4_loop], |
| sizeof(ihevce_wght_offst_t)); |
| |
| /* Store the used as ref for current pic flag */ |
| ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_0][num_ref_pics_list0] |
| .i4_used_by_cur_pic_flag = |
| ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_used_by_cur_pic_flag; |
| |
| num_ref_pics_list0++; |
| i4_loop++; |
| } |
| } |
| else |
| { |
| /* list 1 */ |
| memcpy( |
| &ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_1][num_ref_pics_list1], |
| ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr], |
| sizeof(recon_pic_buf_t)); |
| |
| i4_temp_list = num_ref_pics_list1; |
| /*duplicate pics added to the list*/ |
| while(i4_loop != ps_curr_inp->s_lap_out.as_ref_pics[ref_pics] |
| .i4_num_duplicate_entries_in_ref_list) |
| { |
| /* list 1 */ |
| i4_temp_list++; |
| memcpy( |
| &ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_1][i4_temp_list], |
| ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr], |
| sizeof(recon_pic_buf_t)); |
| i4_loop++; |
| } |
| |
| /* populate weights and offsets corresponding to this ref pic */ |
| memcpy( |
| &ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_1][num_ref_pics_list1] |
| .s_weight_offset, |
| &ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].as_wght_off[0], |
| sizeof(ihevce_wght_offst_t)); |
| |
| /* Store the used as ref for current pic flag */ |
| ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_1][num_ref_pics_list1] |
| .i4_used_by_cur_pic_flag = |
| ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_used_by_cur_pic_flag; |
| |
| num_ref_pics_list1++; |
| i4_loop = 1; |
| /*duplicate pics added to the list*/ |
| while(i4_loop != ps_curr_inp->s_lap_out.as_ref_pics[ref_pics] |
| .i4_num_duplicate_entries_in_ref_list) |
| { |
| /* populate weights and offsets corresponding to this ref pic */ |
| memcpy( |
| &ps_enc_ctxt |
| ->as_pre_enc_ref_lists[i4_ping_pong][LIST_1][num_ref_pics_list1] |
| .s_weight_offset, |
| &ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].as_wght_off[i4_loop], |
| sizeof(ihevce_wght_offst_t)); |
| |
| /* Store the used as ref for current pic flag */ |
| ps_enc_ctxt->as_pre_enc_ref_lists[i4_ping_pong][LIST_1][num_ref_pics_list1] |
| .i4_used_by_cur_pic_flag = |
| ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_used_by_cur_pic_flag; |
| |
| num_ref_pics_list1++; |
| i4_loop++; |
| } |
| } |
| break; |
| } |
| } |
| |
| /* if the reference picture is not found then error */ |
| ASSERT(ctr != ps_enc_ctxt->i4_pre_enc_num_buf_recon_q); |
| } |
| /* sort the reference pics in List0 in descending order POC */ |
| if(num_ref_pics_list0 > 1) |
| { |
| /* run a loop for num ref pics -1 */ |
| for(ctr = 0; ctr < num_ref_pics_list0 - 1; ctr++) |
| { |
| WORD32 max_idx = ctr; |
| recon_pic_buf_t *ps_temp; |
| WORD32 i; |
| |
| for(i = (ctr + 1); i < num_ref_pics_list0; i++) |
| { |
| /* check for poc greater than current ref poc */ |
| if(aps_pre_enc_ref_pic_list[LIST_0][i]->i4_poc > |
| aps_pre_enc_ref_pic_list[LIST_0][max_idx]->i4_poc) |
| { |
| max_idx = i; |
| } |
| } |
| |
| /* if max of remaining is not current, swap the pointers */ |
| if(max_idx != ctr) |
| { |
| ps_temp = aps_pre_enc_ref_pic_list[LIST_0][max_idx]; |
| aps_pre_enc_ref_pic_list[LIST_0][max_idx] = aps_pre_enc_ref_pic_list[LIST_0][ctr]; |
| aps_pre_enc_ref_pic_list[LIST_0][ctr] = ps_temp; |
| } |
| } |
| } |
| |
| /* sort the reference pics in List1 in ascending order POC */ |
| if(num_ref_pics_list1 > 1) |
| { |
| /* run a loop for num ref pics -1 */ |
| for(ctr = 0; ctr < num_ref_pics_list1 - 1; ctr++) |
| { |
| WORD32 min_idx = ctr; |
| recon_pic_buf_t *ps_temp; |
| WORD32 i; |
| |
| for(i = (ctr + 1); i < num_ref_pics_list1; i++) |
| { |
| /* check for p[oc less than current ref poc */ |
| if(aps_pre_enc_ref_pic_list[LIST_1][i]->i4_poc < |
| aps_pre_enc_ref_pic_list[LIST_1][min_idx]->i4_poc) |
| { |
| min_idx = i; |
| } |
| } |
| |
| /* if min of remaining is not current, swap the pointers */ |
| if(min_idx != ctr) |
| { |
| ps_temp = aps_pre_enc_ref_pic_list[LIST_1][min_idx]; |
| aps_pre_enc_ref_pic_list[LIST_1][min_idx] = aps_pre_enc_ref_pic_list[LIST_1][ctr]; |
| aps_pre_enc_ref_pic_list[LIST_1][ctr] = ps_temp; |
| } |
| } |
| } |
| |
| /* call the ME API to update the DPB of HME pyramids coarse layers */ |
| ihevce_coarse_me_frame_dpb_update( |
| ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt, |
| num_ref_pics_list0, |
| num_ref_pics_list1, |
| &aps_pre_enc_ref_pic_list[LIST_0][0], |
| &aps_pre_enc_ref_pic_list[LIST_1][0]); |
| |
| /* Default list creation based on uses as ref pic for current pic flag */ |
| { |
| WORD32 num_ref_pics_list_final = 0; |
| WORD32 list_idx = 0; |
| |
| /* LIST 0 */ |
| /* run a loop for num ref pics in list 0 */ |
| for(ctr = 0; ctr < num_ref_pics_list0; ctr++) |
| { |
| /* check for used as reference flag */ |
| if(1 == aps_pre_enc_ref_pic_list[LIST_0][ctr]->i4_used_by_cur_pic_flag) |
| { |
| /* copy the pointer to the actual valid list idx */ |
| aps_pre_enc_ref_pic_list[LIST_0][list_idx] = aps_pre_enc_ref_pic_list[LIST_0][ctr]; |
| |
| /* increment the valid pic counters and idx */ |
| list_idx++; |
| num_ref_pics_list_final++; |
| } |
| } |
| |
| /* finally store the number of pictures in List0 */ |
| num_ref_pics_list0 = num_ref_pics_list_final; |
| /* LIST 1 */ |
| num_ref_pics_list_final = 0; |
| list_idx = 0; |
| |
| /* run a loop for num ref pics in list 1 */ |
| for(ctr = 0; ctr < num_ref_pics_list1; ctr++) |
| { |
| /* check for used as reference flag */ |
| if(1 == aps_pre_enc_ref_pic_list[LIST_1][ctr]->i4_used_by_cur_pic_flag) |
| { |
| /* copy the pointer to the actual valid list idx */ |
| aps_pre_enc_ref_pic_list[LIST_1][list_idx] = aps_pre_enc_ref_pic_list[LIST_1][ctr]; |
| |
| /* increment the valid pic counters and idx */ |
| list_idx++; |
| num_ref_pics_list_final++; |
| } |
| } |
| |
| /* finally store the number of pictures in List1 */ |
| num_ref_pics_list1 = num_ref_pics_list_final; |
| } |
| /*in case of single active ref picture on L0 and L1, then consider one of them weighted |
| and another non-weighted*/ |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_P_FRAME) |
| { |
| if(num_ref_pics_list0 > 2) |
| { |
| if(aps_pre_enc_ref_pic_list[LIST_0][0]->i4_poc == |
| aps_pre_enc_ref_pic_list[LIST_0][1]->i4_poc) |
| { |
| i4_inc_L0_active_ref_pic = 1; |
| } |
| } |
| } |
| else |
| { |
| if(num_ref_pics_list0 >= 2 && num_ref_pics_list1 >= 2) |
| { |
| if(aps_pre_enc_ref_pic_list[LIST_0][0]->i4_poc == |
| aps_pre_enc_ref_pic_list[LIST_0][1]->i4_poc) |
| { |
| i4_inc_L0_active_ref_pic = 1; |
| } |
| if(aps_pre_enc_ref_pic_list[LIST_1][0]->i4_poc == |
| aps_pre_enc_ref_pic_list[LIST_1][1]->i4_poc) |
| { |
| i4_inc_L1_active_ref_pic = 1; |
| } |
| } |
| } |
| |
| /* append the reference pics in List1 and end of list0 */ |
| for(ctr = 0; ctr < num_ref_pics_list1; ctr++) |
| { |
| aps_pre_enc_ref_pic_list[LIST_0][num_ref_pics_list0 + ctr] = |
| aps_pre_enc_ref_pic_list[LIST_1][ctr]; |
| } |
| |
| /* append the reference pics in List0 and end of list1 */ |
| for(ctr = 0; ctr < num_ref_pics_list0; ctr++) |
| { |
| aps_pre_enc_ref_pic_list[LIST_1][num_ref_pics_list1 + ctr] = |
| aps_pre_enc_ref_pic_list[LIST_0][ctr]; |
| } |
| |
| /* reference list modification for adding duplicate reference */ |
| { |
| |
| } |
| |
| /* popluate the default weights and offsets for disabled cases */ |
| { |
| WORD32 i; |
| |
| /* populate the weights and offsets for all pics in L0 + L1 */ |
| for(i = 0; i < (num_ref_pics_list0 + num_ref_pics_list1); i++) |
| { |
| /* populate the weights and offsets if weighted prediction is disabled */ |
| if(1 == wp_flag) |
| { |
| /* if weights are disabled then populate default values */ |
| if(0 == |
| aps_pre_enc_ref_pic_list[LIST_0][i]->s_weight_offset.u1_luma_weight_enable_flag) |
| { |
| /* set to default values */ |
| aps_pre_enc_ref_pic_list[LIST_0][i]->s_weight_offset.i2_luma_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom); |
| |
| aps_pre_enc_ref_pic_list[LIST_0][i]->s_weight_offset.i2_luma_offset = 0; |
| } |
| } |
| } |
| |
| for(i = 0; i < (num_ref_pics_list0 + num_ref_pics_list1); i++) |
| { |
| /* populate the weights and offsets if weighted prediction is enabled */ |
| if(1 == wp_flag) |
| { |
| /* if weights are disabled then populate default values */ |
| if(0 == |
| aps_pre_enc_ref_pic_list[LIST_1][i]->s_weight_offset.u1_luma_weight_enable_flag) |
| { |
| /* set to default values */ |
| aps_pre_enc_ref_pic_list[LIST_1][i]->s_weight_offset.i2_luma_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom); |
| |
| aps_pre_enc_ref_pic_list[LIST_1][i]->s_weight_offset.i2_luma_offset = 0; |
| } |
| } |
| } |
| } |
| |
| /* run a loop to free the non used reference pics */ |
| for(ctr = 0; ctr < ps_enc_ctxt->i4_pre_enc_num_buf_recon_q; ctr++) |
| { |
| /* if not used as reference */ |
| if(0 == ai4_buf_status[ctr]) |
| { |
| ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr]->i4_is_free = 1; |
| ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr]->i4_poc = -1; |
| } |
| } |
| |
| /* store the number of reference pics in the list for ME/MC etc */ |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0 = num_ref_pics_list0; |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1 = num_ref_pics_list1; |
| |
| #define HME_USE_ONLY_2REF |
| #ifndef HME_USE_ONLY_2REF |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = num_ref_pics_list0; |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = num_ref_pics_list1; |
| #else |
| #if MULTI_REF_ENABLE == 1 |
| if(ps_curr_inp->s_lap_out.i4_quality_preset >= IHEVCE_QUALITY_P3) |
| { |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_P_FRAME) |
| { |
| if(IHEVCE_QUALITY_P6 == ps_curr_inp->s_lap_out.i4_quality_preset) |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = |
| MIN(MAX_NUM_REFS_IN_PPICS_IN_XS25 + 1, num_ref_pics_list0); |
| } |
| else |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = |
| MIN(MAX_NUM_REFS_IN_PPICS_IN_XS25, num_ref_pics_list0); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active += i4_inc_L0_active_ref_pic; |
| } |
| |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = 0; |
| } |
| else |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(3, num_ref_pics_list0); |
| } |
| else |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(2, num_ref_pics_list0); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active += i4_inc_L0_active_ref_pic; |
| } |
| |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = 0; |
| } |
| } |
| else |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(2, num_ref_pics_list0); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = MIN(1, num_ref_pics_list1); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active += i4_inc_L1_active_ref_pic; |
| } |
| else |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(1, num_ref_pics_list0); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = MIN(1, num_ref_pics_list1); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active += i4_inc_L1_active_ref_pic; |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active += i4_inc_L0_active_ref_pic; |
| } |
| } |
| } |
| else |
| { |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_P_FRAME) |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(4, num_ref_pics_list0); |
| else |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(4, num_ref_pics_list0); |
| |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = 0; |
| } |
| else |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(4, num_ref_pics_list0); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = MIN(4, num_ref_pics_list1); |
| } |
| else |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(4, num_ref_pics_list0); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = MIN(4, num_ref_pics_list1); |
| } |
| } |
| } |
| #else |
| { |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_P_FRAME) |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(3, num_ref_pics_list0); |
| else |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(2, num_ref_pics_list0); |
| |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = 0; |
| } |
| else |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(2, num_ref_pics_list0); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = MIN(1, num_ref_pics_list1); |
| } |
| else |
| { |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active = MIN(1, num_ref_pics_list0); |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active = MIN(1, num_ref_pics_list1); |
| } |
| } |
| } |
| #endif |
| #endif |
| |
| return; |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_manage_ref_pics \endif |
| * |
| * \brief |
| * Reference picture management based on delta poc array given by LAP |
| * Populates the reference list after removing non used reference pictures |
| * populates the delta poc of reference pics to be signalled in slice header |
| * |
| * \param[in] encoder context pointer |
| * \param[in] current LAP Encoder buffer pointer |
| * \param[in] current frame process and entropy buffer pointer |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_manage_ref_pics( |
| enc_ctxt_t *ps_enc_ctxt, |
| ihevce_lap_enc_buf_t *ps_curr_inp, |
| slice_header_t *ps_slice_header, |
| WORD32 i4_me_frm_id, |
| WORD32 i4_thrd_id, |
| WORD32 i4_bitrate_instance_id) |
| { |
| WORD32 ctr; |
| WORD32 ref_pics; |
| WORD32 curr_poc, curr_idr_gop_num; |
| WORD32 wp_flag; |
| WORD32 num_ref_pics_list0 = 0; |
| WORD32 num_ref_pics_list1 = 0; |
| WORD32 cra_poc = ps_curr_inp->s_lap_out.i4_assoc_IRAP_poc; |
| WORD32 slice_type = ps_slice_header->i1_slice_type; |
| recon_pic_buf_t *(*aps_ref_list)[HEVCE_MAX_REF_PICS * 2]; |
| recon_pic_buf_t(*aps_ref_list_temp)[HEVCE_MAX_REF_PICS * 2]; |
| WORD32 i4_num_rpics_l0_excl_dup; |
| WORD32 i4_num_rpics_l1_excl_dup; |
| WORD32 i4_inc_L1_active_ref_pic = 0; |
| WORD32 i4_inc_L0_active_ref_pic = 0; |
| WORD32 i4_bridx = i4_bitrate_instance_id; //bitrate instance index |
| WORD32 i4_resolution_id = ps_enc_ctxt->i4_resolution_id; |
| me_enc_rdopt_ctxt_t *ps_cur_out_me_prms; |
| recon_pic_buf_t ***ppps_recon_bufs = ps_enc_ctxt->pps_recon_buf_q; |
| WORD32 i4_num_recon_bufs = ps_enc_ctxt->ai4_num_buf_recon_q[i4_bridx]; |
| |
| ps_cur_out_me_prms = ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id]; |
| |
| /*to support diplicate pics*/ |
| { |
| WORD32 i, j; |
| for(i = 0; i < NUM_REF_LISTS; i++) |
| { |
| for(j = 0; j < HEVCE_MAX_REF_PICS * 2; j++) |
| { |
| ps_cur_out_me_prms->aps_ref_list[i4_bridx][i][j] = |
| &ps_cur_out_me_prms->as_ref_list[i4_bridx][i][j]; |
| } |
| } |
| } |
| |
| aps_ref_list = ps_cur_out_me_prms->aps_ref_list[i4_bridx]; |
| aps_ref_list_temp = ps_cur_out_me_prms->as_ref_list[i4_bridx]; |
| |
| curr_poc = ps_curr_inp->s_lap_out.i4_poc; |
| curr_idr_gop_num = ps_curr_inp->s_lap_out.i4_idr_gop_num; |
| |
| /* Number of reference pics given by LAP should not be greater than max */ |
| ASSERT(HEVCE_MAX_REF_PICS >= ps_curr_inp->s_lap_out.i4_num_ref_pics); |
| |
| /* derive the weighted prediction enable flag based on slice type */ |
| if(BSLICE == slice_type) |
| { |
| wp_flag = ps_curr_inp->s_lap_out.i1_weighted_bipred_flag; |
| } |
| else if(PSLICE == slice_type) |
| { |
| wp_flag = ps_curr_inp->s_lap_out.i1_weighted_pred_flag; |
| } |
| else |
| { |
| wp_flag = 0; |
| } |
| |
| ps_slice_header->s_rplm.i1_ref_pic_list_modification_flag_l0 = 0; |
| ps_slice_header->s_rplm.i1_ref_pic_list_modification_flag_l1 = 0; |
| ASSERT(curr_poc != INVALID_POC); |
| |
| /* run a loop over the number of reference pics given by LAP */ |
| for(ref_pics = 0; ref_pics < ps_curr_inp->s_lap_out.i4_num_ref_pics; ref_pics++) |
| { |
| WORD32 ref_poc; |
| WORD32 i4_loop = 1; |
| WORD32 i4_temp_list; |
| |
| ref_poc = curr_poc + ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_ref_pic_delta_poc; |
| if((0 == curr_poc) && curr_idr_gop_num) |
| { |
| curr_idr_gop_num -= 1; |
| } |
| ASSERT(ref_poc != INVALID_POC); |
| /* run a loop to check the poc based on delta poc array */ |
| for(ctr = 0; ctr < i4_num_recon_bufs; ctr++) |
| { |
| /* if the POC is matching with current ref picture*/ |
| if((ref_poc == ppps_recon_bufs[i4_bridx][ctr]->i4_poc) && |
| (0 == ppps_recon_bufs[i4_bridx][ctr]->i4_is_free) && |
| (curr_idr_gop_num == ppps_recon_bufs[i4_bridx][ctr]->i4_idr_gop_num)) |
| { |
| /* populate the reference lists based on delta poc array */ |
| if((ref_poc < curr_poc) || (0 == curr_poc)) |
| { |
| /* list 0 */ |
| memcpy( |
| &aps_ref_list_temp[LIST_0][num_ref_pics_list0], |
| ppps_recon_bufs[i4_bridx][ctr], |
| sizeof(recon_pic_buf_t)); |
| |
| i4_temp_list = num_ref_pics_list0; |
| |
| /*duplicate pics added to the list*/ |
| while(i4_loop != ps_curr_inp->s_lap_out.as_ref_pics[ref_pics] |
| .i4_num_duplicate_entries_in_ref_list) |
| { |
| i4_temp_list++; |
| /* list 0 */ |
| memcpy( |
| &aps_ref_list_temp[LIST_0][i4_temp_list], |
| ppps_recon_bufs[i4_bridx][ctr], |
| sizeof(recon_pic_buf_t)); |
| i4_loop++; |
| } |
| |
| /* populate weights and offsets corresponding to this ref pic */ |
| memcpy( |
| &aps_ref_list_temp[LIST_0][num_ref_pics_list0].s_weight_offset, |
| &ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].as_wght_off[0], |
| sizeof(ihevce_wght_offst_t)); |
| |
| /* Store the used as ref for current pic flag */ |
| aps_ref_list_temp[LIST_0][num_ref_pics_list0].i4_used_by_cur_pic_flag = |
| ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_used_by_cur_pic_flag; |
| |
| if(wp_flag) |
| { |
| WORD16 i2_luma_weight = (aps_ref_list[LIST_0][num_ref_pics_list0] |
| ->s_weight_offset.i2_luma_weight); |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| else |
| { |
| WORD16 i2_luma_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom); |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0]->s_weight_offset.i2_luma_weight = |
| i2_luma_weight; |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| |
| num_ref_pics_list0++; |
| i4_loop = 1; |
| |
| /*duplicate pics added to the list*/ |
| while(i4_loop != ps_curr_inp->s_lap_out.as_ref_pics[ref_pics] |
| .i4_num_duplicate_entries_in_ref_list) |
| { |
| /* populate weights and offsets corresponding to this ref pic */ |
| memcpy( |
| &aps_ref_list_temp[LIST_0][num_ref_pics_list0].s_weight_offset, |
| &ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].as_wght_off[i4_loop], |
| sizeof(ihevce_wght_offst_t)); |
| |
| /* Store the used as ref for current pic flag */ |
| aps_ref_list_temp[LIST_0][num_ref_pics_list0].i4_used_by_cur_pic_flag = |
| ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_used_by_cur_pic_flag; |
| |
| if(wp_flag) |
| { |
| WORD16 i2_luma_weight = (aps_ref_list[LIST_0][num_ref_pics_list0] |
| ->s_weight_offset.i2_luma_weight); |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| else |
| { |
| WORD16 i2_luma_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom); |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0] |
| ->s_weight_offset.i2_luma_weight = i2_luma_weight; |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_0][num_ref_pics_list0]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| |
| num_ref_pics_list0++; |
| i4_loop++; |
| ps_slice_header->s_rplm.i1_ref_pic_list_modification_flag_l0 = 1; |
| ps_slice_header->s_rplm.i1_ref_pic_list_modification_flag_l1 = 1; |
| } |
| } |
| else |
| { |
| /* list 1 */ |
| memcpy( |
| &aps_ref_list_temp[LIST_1][num_ref_pics_list1], |
| ppps_recon_bufs[i4_bridx][ctr], |
| sizeof(recon_pic_buf_t)); |
| i4_temp_list = num_ref_pics_list1; |
| /*duplicate pics added to the list*/ |
| while(i4_loop != ps_curr_inp->s_lap_out.as_ref_pics[ref_pics] |
| .i4_num_duplicate_entries_in_ref_list) |
| { |
| i4_temp_list++; |
| /* list 1 */ |
| memcpy( |
| &aps_ref_list_temp[LIST_1][i4_temp_list], |
| ppps_recon_bufs[i4_bridx][ctr], |
| sizeof(recon_pic_buf_t)); |
| i4_loop++; |
| } |
| |
| /* populate weights and offsets corresponding to this ref pic */ |
| memcpy( |
| &aps_ref_list_temp[LIST_1][num_ref_pics_list1].s_weight_offset, |
| &ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].as_wght_off[0], |
| sizeof(ihevce_wght_offst_t)); |
| |
| /* Store the used as ref for current pic flag */ |
| aps_ref_list_temp[LIST_1][num_ref_pics_list1].i4_used_by_cur_pic_flag = |
| ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_used_by_cur_pic_flag; |
| |
| if(wp_flag) |
| { |
| WORD16 i2_luma_weight = (aps_ref_list[LIST_1][num_ref_pics_list1] |
| ->s_weight_offset.i2_luma_weight); |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| else |
| { |
| WORD16 i2_luma_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom); |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1]->s_weight_offset.i2_luma_weight = |
| i2_luma_weight; |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| |
| num_ref_pics_list1++; |
| i4_loop = 1; |
| /*duplicate pics added to the list*/ |
| while(i4_loop != ps_curr_inp->s_lap_out.as_ref_pics[ref_pics] |
| .i4_num_duplicate_entries_in_ref_list) |
| { |
| /* populate weights and offsets corresponding to this ref pic */ |
| memcpy( |
| &aps_ref_list_temp[LIST_1][num_ref_pics_list1].s_weight_offset, |
| &ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].as_wght_off[i4_loop], |
| sizeof(ihevce_wght_offst_t)); |
| |
| /* Store the used as ref for current pic flag */ |
| aps_ref_list_temp[LIST_1][num_ref_pics_list1].i4_used_by_cur_pic_flag = |
| ps_curr_inp->s_lap_out.as_ref_pics[ref_pics].i4_used_by_cur_pic_flag; |
| |
| if(wp_flag) |
| { |
| WORD16 i2_luma_weight = (aps_ref_list[LIST_1][num_ref_pics_list1] |
| ->s_weight_offset.i2_luma_weight); |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| else |
| { |
| WORD16 i2_luma_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom); |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1] |
| ->s_weight_offset.i2_luma_weight = i2_luma_weight; |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_1][num_ref_pics_list1]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| |
| num_ref_pics_list1++; |
| i4_loop++; |
| ps_slice_header->s_rplm.i1_ref_pic_list_modification_flag_l1 = 1; |
| ps_slice_header->s_rplm.i1_ref_pic_list_modification_flag_l0 = 1; |
| } |
| } |
| break; |
| } |
| } |
| |
| /* if the reference picture is not found then error */ |
| ASSERT(ctr != i4_num_recon_bufs); |
| } |
| |
| i4_num_rpics_l0_excl_dup = num_ref_pics_list0; |
| i4_num_rpics_l1_excl_dup = num_ref_pics_list1; |
| |
| /* sort the reference pics in List0 in descending order POC */ |
| if(num_ref_pics_list0 > 1) |
| { |
| /* run a loop for num ref pics -1 */ |
| for(ctr = 0; ctr < num_ref_pics_list0 - 1; ctr++) |
| { |
| WORD32 max_idx = ctr; |
| recon_pic_buf_t *ps_temp; |
| WORD32 i; |
| |
| for(i = (ctr + 1); i < num_ref_pics_list0; i++) |
| { |
| /* check for poc greater than current ref poc */ |
| if(aps_ref_list[LIST_0][i]->i4_poc > aps_ref_list[LIST_0][max_idx]->i4_poc) |
| { |
| max_idx = i; |
| } |
| } |
| |
| /* if max of remaining is not current, swap the pointers */ |
| if(max_idx != ctr) |
| { |
| ps_temp = aps_ref_list[LIST_0][max_idx]; |
| aps_ref_list[LIST_0][max_idx] = aps_ref_list[LIST_0][ctr]; |
| aps_ref_list[LIST_0][ctr] = ps_temp; |
| } |
| } |
| } |
| |
| /* sort the reference pics in List1 in ascending order POC */ |
| if(num_ref_pics_list1 > 1) |
| { |
| /* run a loop for num ref pics -1 */ |
| for(ctr = 0; ctr < num_ref_pics_list1 - 1; ctr++) |
| { |
| WORD32 min_idx = ctr; |
| recon_pic_buf_t *ps_temp; |
| WORD32 i; |
| |
| for(i = (ctr + 1); i < num_ref_pics_list1; i++) |
| { |
| /* check for p[oc less than current ref poc */ |
| if(aps_ref_list[LIST_1][i]->i4_poc < aps_ref_list[LIST_1][min_idx]->i4_poc) |
| { |
| min_idx = i; |
| } |
| } |
| |
| /* if min of remaining is not current, swap the pointers */ |
| if(min_idx != ctr) |
| { |
| ps_temp = aps_ref_list[LIST_1][min_idx]; |
| aps_ref_list[LIST_1][min_idx] = aps_ref_list[LIST_1][ctr]; |
| aps_ref_list[LIST_1][ctr] = ps_temp; |
| } |
| } |
| } |
| |
| /* popluate the slice header parameters to signal delta POCs and use flags */ |
| { |
| WORD32 i; |
| WORD32 prev_poc = curr_poc; |
| |
| ps_slice_header->s_stref_picset.i1_inter_ref_pic_set_prediction_flag = 0; |
| |
| ps_slice_header->s_stref_picset.i1_num_neg_pics = num_ref_pics_list0; |
| |
| ps_slice_header->s_stref_picset.i1_num_pos_pics = num_ref_pics_list1; |
| |
| ps_slice_header->s_stref_picset.i1_num_ref_idc = -1; |
| |
| /* populate the delta POCs of reference pics */ |
| i = 0; |
| |
| for(ctr = 0; ctr < i4_num_rpics_l0_excl_dup; ctr++) |
| { |
| WORD32 ref_poc_l0 = aps_ref_list[LIST_0][i]->i4_poc; |
| |
| ps_slice_header->s_stref_picset.ai2_delta_poc[ctr] = prev_poc - ref_poc_l0; |
| ps_slice_header->s_stref_picset.ai1_used[ctr] = |
| aps_ref_list[LIST_0][i]->i4_used_by_cur_pic_flag; |
| |
| /* check if this picture has to be used as reference */ |
| if(1 == ps_slice_header->s_stref_picset.ai1_used[ctr]) |
| { |
| /* check for CRA poc related use flag signalling */ |
| ps_slice_header->s_stref_picset.ai1_used[ctr] = |
| (curr_poc > cra_poc) ? (ref_poc_l0 >= cra_poc) : (slice_type != ISLICE); |
| } |
| if(!(prev_poc - ref_poc_l0)) |
| { |
| ctr -= 1; |
| i4_num_rpics_l0_excl_dup -= 1; |
| } |
| prev_poc = ref_poc_l0; |
| |
| i++; |
| } |
| |
| i = 0; |
| prev_poc = curr_poc; |
| for(; ctr < (i4_num_rpics_l0_excl_dup + i4_num_rpics_l1_excl_dup); ctr++) |
| { |
| WORD32 ref_poc_l1 = aps_ref_list[LIST_1][i]->i4_poc; |
| |
| ps_slice_header->s_stref_picset.ai2_delta_poc[ctr] = ref_poc_l1 - prev_poc; |
| |
| ps_slice_header->s_stref_picset.ai1_used[ctr] = |
| aps_ref_list[LIST_1][i]->i4_used_by_cur_pic_flag; |
| |
| /* check if this picture has to be used as reference */ |
| if(1 == ps_slice_header->s_stref_picset.ai1_used[ctr]) |
| { |
| /* check for CRA poc related use flag signalling */ |
| ps_slice_header->s_stref_picset.ai1_used[ctr] = |
| (curr_poc > cra_poc) ? (ref_poc_l1 >= cra_poc) : (slice_type != ISLICE); |
| /* (slice_type != ISLICE); */ |
| } |
| if(!(ref_poc_l1 - prev_poc)) |
| { |
| ctr -= 1; |
| i4_num_rpics_l1_excl_dup -= 1; |
| } |
| prev_poc = ref_poc_l1; |
| i++; |
| } |
| ps_slice_header->s_stref_picset.i1_num_neg_pics = i4_num_rpics_l0_excl_dup; |
| |
| ps_slice_header->s_stref_picset.i1_num_pos_pics = i4_num_rpics_l1_excl_dup; |
| |
| if(IV_IDR_FRAME == ps_curr_inp->s_lap_out.i4_pic_type) |
| { |
| ps_slice_header->s_stref_picset.i1_num_neg_pics = 0; |
| ps_slice_header->s_stref_picset.i1_num_pos_pics = 0; |
| } |
| |
| /* not used so set to -1 */ |
| memset(&ps_slice_header->s_stref_picset.ai1_ref_idc[0], -1, MAX_DPB_SIZE); |
| } |
| /* call the ME API to update the DPB of HME pyramids |
| Upadate list for reference bit-rate only */ |
| if(0 == i4_bridx) |
| { |
| ihevce_me_frame_dpb_update( |
| ps_enc_ctxt->s_module_ctxt.pv_me_ctxt, |
| num_ref_pics_list0, |
| num_ref_pics_list1, |
| &aps_ref_list[LIST_0][0], |
| &aps_ref_list[LIST_1][0], |
| i4_thrd_id); |
| } |
| |
| /* Default list creation based on uses as ref pic for current pic flag */ |
| { |
| WORD32 num_ref_pics_list_final = 0; |
| WORD32 list_idx = 0; |
| |
| /* LIST 0 */ |
| /* run a loop for num ref pics in list 0 */ |
| for(ctr = 0; ctr < num_ref_pics_list0; ctr++) |
| { |
| /* check for used as reference flag */ |
| if(1 == aps_ref_list[LIST_0][ctr]->i4_used_by_cur_pic_flag) |
| { |
| /* copy the pointer to the actual valid list idx */ |
| aps_ref_list[LIST_0][list_idx] = aps_ref_list[LIST_0][ctr]; |
| |
| /* increment the valid pic counters and idx */ |
| list_idx++; |
| num_ref_pics_list_final++; |
| } |
| } |
| |
| /* finally store the number of pictures in List0 */ |
| num_ref_pics_list0 = num_ref_pics_list_final; |
| |
| /* LIST 1 */ |
| num_ref_pics_list_final = 0; |
| list_idx = 0; |
| |
| /* run a loop for num ref pics in list 1 */ |
| for(ctr = 0; ctr < num_ref_pics_list1; ctr++) |
| { |
| /* check for used as reference flag */ |
| if(1 == aps_ref_list[LIST_1][ctr]->i4_used_by_cur_pic_flag) |
| { |
| /* copy the pointer to the actual valid list idx */ |
| aps_ref_list[LIST_1][list_idx] = aps_ref_list[LIST_1][ctr]; |
| |
| /* increment the valid pic counters and idx */ |
| list_idx++; |
| num_ref_pics_list_final++; |
| } |
| } |
| |
| /* finally store the number of pictures in List1 */ |
| num_ref_pics_list1 = num_ref_pics_list_final; |
| } |
| /*in case of single active ref picture on L0 and L1, then consider one of them weighted |
| and another non-weighted*/ |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_P_FRAME) |
| { |
| if(num_ref_pics_list0 > 2) |
| { |
| if(aps_ref_list[LIST_0][0]->i4_poc == aps_ref_list[LIST_0][1]->i4_poc) |
| { |
| i4_inc_L0_active_ref_pic = 1; |
| } |
| } |
| } |
| else |
| { |
| if(num_ref_pics_list0 >= 2 && num_ref_pics_list1 >= 2) |
| { |
| if(aps_ref_list[LIST_0][0]->i4_poc == aps_ref_list[LIST_0][1]->i4_poc) |
| { |
| i4_inc_L0_active_ref_pic = 1; |
| } |
| |
| if(aps_ref_list[LIST_1][0]->i4_poc == aps_ref_list[LIST_1][1]->i4_poc) |
| { |
| i4_inc_L1_active_ref_pic = 1; |
| } |
| } |
| } |
| /* append the reference pics in List1 and end of list0 */ |
| for(ctr = 0; ctr < num_ref_pics_list1; ctr++) |
| { |
| aps_ref_list[LIST_0][num_ref_pics_list0 + ctr] = aps_ref_list[LIST_1][ctr]; |
| } |
| |
| /* append the reference pics in List0 and end of list1 */ |
| for(ctr = 0; ctr < num_ref_pics_list0; ctr++) |
| { |
| aps_ref_list[LIST_1][num_ref_pics_list1 + ctr] = aps_ref_list[LIST_0][ctr]; |
| } |
| |
| /* reference list modification for adding duplicate reference */ |
| { |
| WORD32 i4_latest_idx = 0; |
| recon_pic_buf_t *ps_ref_list_cur; |
| recon_pic_buf_t *ps_ref_list_prev; |
| /*List 0*/ |
| ps_ref_list_cur = aps_ref_list[LIST_0][0]; |
| ps_ref_list_prev = ps_ref_list_cur; |
| for(ctr = 0; ctr < (num_ref_pics_list0 + num_ref_pics_list1); ctr++) |
| { |
| if(ps_ref_list_cur->i4_poc != ps_ref_list_prev->i4_poc) |
| { |
| i4_latest_idx++; |
| } |
| ps_ref_list_prev = ps_ref_list_cur; |
| ps_slice_header->s_rplm.i4_ref_poc_l0[ctr] = ps_ref_list_cur->i4_poc; |
| ps_slice_header->s_rplm.i1_list_entry_l0[ctr] = i4_latest_idx; |
| if((ctr + 1) < (num_ref_pics_list0 + num_ref_pics_list1)) |
| { |
| ps_ref_list_cur = aps_ref_list[LIST_0][ctr + 1]; |
| } |
| } /*end for*/ |
| |
| /*LIST 1*/ |
| i4_latest_idx = 0; |
| ps_ref_list_cur = aps_ref_list[LIST_1][0]; |
| ps_ref_list_prev = ps_ref_list_cur; |
| for(ctr = 0; ctr < (num_ref_pics_list0 + num_ref_pics_list1); ctr++) |
| { |
| if(ps_ref_list_cur->i4_poc != ps_ref_list_prev->i4_poc) |
| { |
| i4_latest_idx++; |
| } |
| ps_ref_list_prev = ps_ref_list_cur; |
| ps_slice_header->s_rplm.i4_ref_poc_l1[ctr] = ps_ref_list_cur->i4_poc; |
| ps_slice_header->s_rplm.i1_list_entry_l1[ctr] = i4_latest_idx; |
| if((ctr + 1) < (num_ref_pics_list0 + num_ref_pics_list1)) |
| { |
| ps_ref_list_cur = aps_ref_list[LIST_1][ctr + 1]; |
| } |
| } /*end for*/ |
| } |
| |
| /* set number of active references used for l0 and l1 in slice hdr */ |
| ps_slice_header->i1_num_ref_idx_active_override_flag = 1; |
| ps_slice_header->i1_num_ref_idx_l0_active = num_ref_pics_list0 + num_ref_pics_list1; |
| if(BSLICE == slice_type) |
| { |
| /* i1_num_ref_idx_l1_active applicable only for B pics */ |
| ps_slice_header->i1_num_ref_idx_l1_active = num_ref_pics_list0 + num_ref_pics_list1; |
| } |
| /* popluate the slice header parameters with weights and offsets */ |
| { |
| WORD32 i; |
| |
| /* populate the log 2 weight denom if weighted prediction is enabled */ |
| if(1 == wp_flag) |
| { |
| ps_slice_header->s_wt_ofst.i1_chroma_log2_weight_denom = |
| ps_curr_inp->s_lap_out.i4_log2_chroma_wght_denom; |
| ps_slice_header->s_wt_ofst.i1_luma_log2_weight_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| |
| /* populate the weights and offsets for all pics in L0 + L1 */ |
| for(i = 0; i < (num_ref_pics_list0 + num_ref_pics_list1); i++) |
| { |
| /* populate the weights and offsets if weighted prediction is enabled */ |
| if(1 == wp_flag) |
| { |
| ps_slice_header->s_wt_ofst.i1_luma_weight_l0_flag[i] = |
| aps_ref_list[LIST_0][i]->s_weight_offset.u1_luma_weight_enable_flag; |
| |
| /* if weights are enabled then copy to slice header */ |
| if(1 == ps_slice_header->s_wt_ofst.i1_luma_weight_l0_flag[i]) |
| { |
| ps_slice_header->s_wt_ofst.i2_luma_weight_l0[i] = |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_luma_weight; |
| ps_slice_header->s_wt_ofst.i2_luma_offset_l0[i] = |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_luma_offset; |
| |
| { |
| WORD16 i2_luma_weight = |
| (aps_ref_list[LIST_0][i]->s_weight_offset.i2_luma_weight); |
| |
| aps_ref_list[LIST_0][i]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_0][i]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| } |
| else |
| { |
| WORD16 i2_luma_weight = (1 << ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom); |
| |
| /* set to default values */ |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_luma_weight = (i2_luma_weight); |
| |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_luma_offset = 0; |
| |
| aps_ref_list[LIST_0][i]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_0][i]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| |
| ps_slice_header->s_wt_ofst.i1_chroma_weight_l0_flag[i] = |
| aps_ref_list[LIST_0][i]->s_weight_offset.u1_chroma_weight_enable_flag; |
| |
| /* if weights are enabled then copy to slice header */ |
| if(1 == ps_slice_header->s_wt_ofst.i1_chroma_weight_l0_flag[i]) |
| { |
| ps_slice_header->s_wt_ofst.i2_chroma_weight_l0_cb[i] = |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_cb_weight; |
| ps_slice_header->s_wt_ofst.i2_chroma_offset_l0_cb[i] = |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_cb_offset; |
| |
| ps_slice_header->s_wt_ofst.i2_chroma_weight_l0_cr[i] = |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_cr_weight; |
| ps_slice_header->s_wt_ofst.i2_chroma_offset_l0_cr[i] = |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_cr_offset; |
| } |
| else |
| { |
| /* set to default values */ |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_cb_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_chroma_wght_denom); |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_cr_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_chroma_wght_denom); |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_cb_offset = 0; |
| aps_ref_list[LIST_0][i]->s_weight_offset.i2_cr_offset = 0; |
| } |
| } |
| } |
| |
| for(i = 0; i < (num_ref_pics_list0 + num_ref_pics_list1); i++) |
| { |
| /* populate the weights and offsets if weighted prediction is enabled */ |
| if(1 == wp_flag) |
| { |
| ps_slice_header->s_wt_ofst.i1_luma_weight_l1_flag[i] = |
| aps_ref_list[LIST_1][i]->s_weight_offset.u1_luma_weight_enable_flag; |
| |
| /* if weights are enabled then copy to slice header */ |
| if(1 == ps_slice_header->s_wt_ofst.i1_luma_weight_l1_flag[i]) |
| { |
| ps_slice_header->s_wt_ofst.i2_luma_weight_l1[i] = |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_luma_weight; |
| ps_slice_header->s_wt_ofst.i2_luma_offset_l1[i] = |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_luma_offset; |
| |
| { |
| WORD16 i2_luma_weight = |
| (aps_ref_list[LIST_1][i]->s_weight_offset.i2_luma_weight); |
| |
| aps_ref_list[LIST_1][i]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_1][i]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| } |
| else |
| { |
| WORD16 i2_luma_weight = (1 << ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom); |
| |
| /* set to default values */ |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_luma_weight = (i2_luma_weight); |
| |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_luma_offset = 0; |
| |
| aps_ref_list[LIST_1][i]->i4_inv_luma_wt = |
| ((1 << 15) + (i2_luma_weight >> 1)) / i2_luma_weight; |
| |
| aps_ref_list[LIST_1][i]->i4_log2_wt_denom = |
| ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom; |
| } |
| |
| ps_slice_header->s_wt_ofst.i1_chroma_weight_l1_flag[i] = |
| aps_ref_list[LIST_1][i]->s_weight_offset.u1_chroma_weight_enable_flag; |
| |
| /* if weights are enabled then copy to slice header */ |
| if(1 == ps_slice_header->s_wt_ofst.i1_chroma_weight_l1_flag[i]) |
| { |
| ps_slice_header->s_wt_ofst.i2_chroma_weight_l1_cb[i] = |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_cb_weight; |
| ps_slice_header->s_wt_ofst.i2_chroma_offset_l1_cb[i] = |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_cb_offset; |
| |
| ps_slice_header->s_wt_ofst.i2_chroma_weight_l1_cr[i] = |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_cr_weight; |
| ps_slice_header->s_wt_ofst.i2_chroma_offset_l1_cr[i] = |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_cr_offset; |
| } |
| else |
| { |
| /* set to default values */ |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_cb_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_chroma_wght_denom); |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_cr_weight = |
| (1 << ps_curr_inp->s_lap_out.i4_log2_chroma_wght_denom); |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_cb_offset = 0; |
| aps_ref_list[LIST_1][i]->s_weight_offset.i2_cr_offset = 0; |
| } |
| } |
| } |
| } |
| |
| /* store the number of reference pics in the list for ME/MC etc */ |
| ps_enc_ctxt->i4_num_ref_l0 = num_ref_pics_list0; |
| ps_enc_ctxt->i4_num_ref_l1 = num_ref_pics_list1; |
| |
| #define HME_USE_ONLY_2REF |
| #ifndef HME_USE_ONLY_2REF |
| ps_enc_ctxt->i4_num_ref_l0_active = num_ref_pics_list0; |
| ps_enc_ctxt->i4_num_ref_l1_active = num_ref_pics_list1; |
| #else |
| #if MULTI_REF_ENABLE == 1 |
| if(ps_curr_inp->s_lap_out.i4_quality_preset >= IHEVCE_QUALITY_P3) |
| { |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_P_FRAME) |
| { |
| if(ps_curr_inp->s_lap_out.i4_quality_preset == IHEVCE_QUALITY_P6) |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = |
| MIN(MAX_NUM_REFS_IN_PPICS_IN_XS25 + 1, num_ref_pics_list0); |
| } |
| else |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = |
| MIN(MAX_NUM_REFS_IN_PPICS_IN_XS25, num_ref_pics_list0); |
| |
| ps_enc_ctxt->i4_num_ref_l0_active += i4_inc_L0_active_ref_pic; |
| } |
| } |
| else |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(3, num_ref_pics_list0); |
| } |
| else |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(2, num_ref_pics_list0); |
| ps_enc_ctxt->i4_num_ref_l0_active += i4_inc_L0_active_ref_pic; |
| } |
| } |
| |
| ps_enc_ctxt->i4_num_ref_l1_active = 0; |
| } |
| else |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(2, num_ref_pics_list0); |
| ps_enc_ctxt->i4_num_ref_l1_active = MIN(1, num_ref_pics_list1); |
| ps_enc_ctxt->i4_num_ref_l1_active += i4_inc_L1_active_ref_pic; |
| } |
| else |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(1, num_ref_pics_list0); |
| ps_enc_ctxt->i4_num_ref_l1_active = MIN(1, num_ref_pics_list1); |
| |
| ps_enc_ctxt->i4_num_ref_l1_active += i4_inc_L1_active_ref_pic; |
| ps_enc_ctxt->i4_num_ref_l0_active += i4_inc_L0_active_ref_pic; |
| } |
| } |
| } |
| else |
| { |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_P_FRAME) |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(4, num_ref_pics_list0); |
| else |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(4, num_ref_pics_list0); |
| |
| ps_enc_ctxt->i4_num_ref_l1_active = 0; |
| } |
| else |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(4, num_ref_pics_list0); |
| ps_enc_ctxt->i4_num_ref_l1_active = MIN(4, num_ref_pics_list1); |
| } |
| else |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(4, num_ref_pics_list0); |
| ps_enc_ctxt->i4_num_ref_l1_active = MIN(4, num_ref_pics_list1); |
| } |
| } |
| } |
| #else |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_P_FRAME) |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(3, num_ref_pics_list0); |
| else |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(2, num_ref_pics_list0); |
| |
| ps_enc_ctxt->i4_num_ref_l1_active = 0; |
| } |
| else |
| { |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(2, num_ref_pics_list0); |
| ps_enc_ctxt->i4_num_ref_l1_active = MIN(1, num_ref_pics_list1); |
| } |
| else |
| { |
| ps_enc_ctxt->i4_num_ref_l0_active = MIN(1, num_ref_pics_list0); |
| ps_enc_ctxt->i4_num_ref_l1_active = MIN(1, num_ref_pics_list1); |
| } |
| } |
| #endif |
| |
| #endif |
| |
| ps_slice_header->i1_num_ref_idx_l0_active = MAX(1, ps_enc_ctxt->i4_num_ref_l0_active); |
| if(BSLICE == slice_type) |
| { |
| /* i1_num_ref_idx_l1_active applicable only for B pics */ |
| ps_slice_header->i1_num_ref_idx_l1_active = MAX(1, ps_enc_ctxt->i4_num_ref_l1_active); |
| } |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| /* If Interlace field is enabled, p field following an cra I field should have only one ref frame */ |
| WORD32 cra_second_poc = cra_poc + 1; |
| |
| if(curr_poc == cra_second_poc) |
| { |
| /* set number of active references used for l0 and l1 for me */ |
| ps_enc_ctxt->i4_num_ref_l0_active = 1; |
| ps_enc_ctxt->i4_num_ref_l1_active = 0; |
| |
| /* set number of active references used for l0 and l1 in slice hdr */ |
| ps_slice_header->i1_num_ref_idx_active_override_flag = 1; |
| ps_slice_header->i1_num_ref_idx_l0_active = |
| ps_enc_ctxt->i4_num_ref_l0 + ps_enc_ctxt->i4_num_ref_l1; |
| } |
| } |
| return; |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_get_frame_lambda_prms \endif |
| * |
| * \brief |
| * Function whihc calculates the Lambda params for current picture |
| * |
| * \param[in] ps_enc_ctxt : encoder ctxt pointer |
| * \param[in] ps_cur_pic_ctxt : current pic ctxt |
| * \param[in] i4_cur_frame_qp : current pic QP |
| * \param[in] first_field : is first field flag |
| * \param[in] i4_temporal_lyr_id : Current picture layer id |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_get_frame_lambda_prms( |
| enc_ctxt_t *ps_enc_ctxt, |
| pre_enc_me_ctxt_t *ps_cur_pic_ctxt, |
| WORD32 i4_cur_frame_qp, |
| WORD32 first_field, |
| WORD32 i4_is_ref_pic, |
| WORD32 i4_temporal_lyr_id, |
| double f_i_pic_lamda_modifier, |
| WORD32 i4_inst_id, |
| WORD32 i4_lambda_type) |
| { |
| double lambda_modifier = CONST_LAMDA_MOD_VAL; |
| double lambda_uv_modifier = CONST_LAMDA_MOD_VAL; |
| double lambda = 0; |
| double lambda_uv; |
| WORD32 i4_use_const_lamda_modifier; |
| |
| /* initialize lambda based on frm qp, slice type, num b and temporal id */ |
| /* This lamba calculation mimics the jctvc doc (TODO add doc number */ |
| |
| WORD32 num_b_frms = |
| (1 << ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_max_temporal_layers) - 1; |
| WORD32 chroma_qp = (ps_enc_ctxt->ps_stat_prms->s_src_prms.i4_chr_format == IV_YUV_422SP_UV) |
| ? MIN(i4_cur_frame_qp, 51) |
| : gai1_ihevc_chroma_qp_scale[i4_cur_frame_qp + MAX_QP_BD_OFFSET]; |
| |
| WORD32 i4_qp_bdoffset = |
| 6 * (ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.i4_internal_bit_depth - 8); |
| WORD32 slice_type = ps_cur_pic_ctxt->s_slice_hdr.i1_slice_type; |
| |
| (void)first_field; |
| (void)i4_is_ref_pic; |
| (void)i4_temporal_lyr_id; |
| i4_use_const_lamda_modifier = USE_CONSTANT_LAMBDA_MODIFIER; |
| i4_use_const_lamda_modifier = i4_use_const_lamda_modifier || |
| ((ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_vqet & |
| (1 << BITPOS_IN_VQ_TOGGLE_FOR_CONTROL_TOGGLER)) && |
| ((ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_vqet & |
| (1 << BITPOS_IN_VQ_TOGGLE_FOR_ENABLING_NOISE_PRESERVATION)) || |
| (ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_vqet & |
| (1 << BITPOS_IN_VQ_TOGGLE_FOR_ENABLING_PSYRDOPT_1)) || |
| (ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_vqet & |
| (1 << BITPOS_IN_VQ_TOGGLE_FOR_ENABLING_PSYRDOPT_2)) || |
| (ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_vqet & |
| (1 << BITPOS_IN_VQ_TOGGLE_FOR_ENABLING_PSYRDOPT_3)))); |
| |
| /* lambda modifier is the dependent on slice type and temporal id */ |
| if(ISLICE == slice_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; |
| lambda_uv_modifier = lambda_modifier; |
| if(i4_use_const_lamda_modifier) |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_modifier = f_i_pic_lamda_modifier; |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_uv_modifier = f_i_pic_lamda_modifier; |
| } |
| else |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_modifier = lambda_modifier; |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_uv_modifier = lambda_uv_modifier; |
| } |
| } |
| else if(PSLICE == slice_type) |
| { |
| if(first_field) |
| lambda_modifier = 0.442; //0.442*0.8; |
| else |
| lambda_modifier = 0.442; |
| lambda_uv_modifier = lambda_modifier; |
| if(i4_use_const_lamda_modifier) |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_modifier = CONST_LAMDA_MOD_VAL; |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_uv_modifier = CONST_LAMDA_MOD_VAL; |
| } |
| else |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_modifier = lambda_modifier; |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_uv_modifier = lambda_uv_modifier; |
| } |
| } |
| else |
| { |
| /* BSLICE */ |
| if(1 == i4_is_ref_pic) |
| { |
| lambda_modifier = 0.3536; |
| } |
| else if(2 == i4_is_ref_pic) |
| { |
| lambda_modifier = 0.45; |
| } |
| else |
| { |
| lambda_modifier = 0.68; |
| } |
| lambda_uv_modifier = lambda_modifier; |
| if(i4_use_const_lamda_modifier) |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_modifier = CONST_LAMDA_MOD_VAL; |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_uv_modifier = CONST_LAMDA_MOD_VAL; |
| } |
| else |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_modifier = lambda_modifier; |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].lambda_uv_modifier = lambda_uv_modifier; |
| } |
| /* 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_temporal_lyr_id) |
| { |
| lambda_modifier *= CLIP3((((double)(i4_cur_frame_qp - 12)) / 6.0), 2.00, 4.00); |
| lambda_uv_modifier *= CLIP3((((double)(chroma_qp - 12)) / 6.0), 2.00, 4.00); |
| } |
| } |
| } |
| if(i4_use_const_lamda_modifier) |
| { |
| if(ISLICE == slice_type) |
| { |
| lambda_modifier = f_i_pic_lamda_modifier; |
| lambda_uv_modifier = f_i_pic_lamda_modifier; |
| } |
| else |
| { |
| lambda_modifier = CONST_LAMDA_MOD_VAL; |
| lambda_uv_modifier = CONST_LAMDA_MOD_VAL; |
| } |
| } |
| |
| switch(i4_lambda_type) |
| { |
| case 0: |
| { |
| i4_qp_bdoffset = 0; |
| |
| lambda = pow(2.0, (((double)(i4_cur_frame_qp + i4_qp_bdoffset - 12)) / 3.0)); |
| lambda_uv = pow(2.0, (((double)(chroma_qp + i4_qp_bdoffset - 12)) / 3.0)); |
| |
| /* modify the base lambda according to lambda modifier */ |
| lambda *= lambda_modifier; |
| lambda_uv *= lambda_uv_modifier; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].u4_chroma_cost_weighing_factor = |
| (UWORD32)((lambda / lambda_uv) * (1 << CHROMA_COST_WEIGHING_FACTOR_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_qf = |
| (LWORD64)(lambda * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_chroma_qf = |
| (LWORD64)(lambda_uv * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_sad_lambda_qf = |
| (WORD32)(sqrt(lambda) * (1 << LAMBDA_Q_SHIFT)); |
| if(i4_use_const_lamda_modifier) |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_lambda_qf = |
| (WORD32)((sqrt(lambda)) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf = |
| (WORD32)(sqrt(lambda) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf = |
| (WORD32)((sqrt(lambda)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| else |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_lambda_qf = |
| (WORD32)((sqrt(lambda) / 1.5) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf = |
| (WORD32)(sqrt(lambda * 1.5) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf = |
| (WORD32)((sqrt(lambda * 1.5)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_type2_lambda_chroma_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_chroma_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_sad_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_sad_lambda_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_lambda_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf; |
| |
| break; |
| } |
| case 1: |
| { |
| lambda = pow(2.0, (((double)(i4_cur_frame_qp + i4_qp_bdoffset - 12)) / 3.0)); |
| lambda_uv = pow(2.0, (((double)(chroma_qp + i4_qp_bdoffset - 12)) / 3.0)); |
| |
| /* modify the base lambda according to lambda modifier */ |
| lambda *= lambda_modifier; |
| lambda_uv *= lambda_uv_modifier; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].u4_chroma_cost_weighing_factor = |
| (UWORD32)((lambda / lambda_uv) * (1 << CHROMA_COST_WEIGHING_FACTOR_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_qf = |
| (LWORD64)(lambda * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_chroma_qf = |
| (LWORD64)(lambda_uv * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_sad_lambda_qf = |
| (WORD32)(sqrt(lambda) * (1 << LAMBDA_Q_SHIFT)); |
| if(i4_use_const_lamda_modifier) |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_lambda_qf = |
| (WORD32)((sqrt(lambda)) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf = |
| (WORD32)(sqrt(lambda) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf = |
| (WORD32)((sqrt(lambda)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| else |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_lambda_qf = |
| (WORD32)((sqrt(lambda) / 1.5) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf = |
| (WORD32)(sqrt(lambda * 1.5) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf = |
| (WORD32)((sqrt(lambda * 1.5)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_type2_lambda_chroma_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_chroma_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_sad_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_sad_lambda_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_lambda_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_type2_lambda_qf = |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf; |
| |
| break; |
| } |
| case 2: |
| { |
| lambda = pow(2.0, (((double)(i4_cur_frame_qp + i4_qp_bdoffset - 12)) / 3.0)); |
| lambda_uv = pow(2.0, (((double)(chroma_qp + i4_qp_bdoffset - 12)) / 3.0)); |
| |
| /* modify the base lambda according to lambda modifier */ |
| lambda *= lambda_modifier; |
| lambda_uv *= lambda_uv_modifier; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].u4_chroma_cost_weighing_factor = |
| (UWORD32)((lambda / lambda_uv) * (1 << CHROMA_COST_WEIGHING_FACTOR_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_qf = |
| (LWORD64)(lambda * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_lambda_chroma_qf = |
| (LWORD64)(lambda_uv * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_sad_lambda_qf = |
| (WORD32)(sqrt(lambda) * (1 << LAMBDA_Q_SHIFT)); |
| |
| if(i4_use_const_lamda_modifier) |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_lambda_qf = |
| (WORD32)((sqrt(lambda)) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf = |
| (WORD32)(sqrt(lambda) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf = |
| (WORD32)((sqrt(lambda)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| else |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_lambda_qf = |
| (WORD32)((sqrt(lambda) / 1.5) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf = |
| (WORD32)(sqrt(lambda * 1.5) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf = |
| (WORD32)((sqrt(lambda * 1.5)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| /* lambda corresponding to 8- bit, for metrics based on 8- bit ( Example 8bit SAD in encloop)*/ |
| |
| lambda = pow(2.0, (((double)(i4_cur_frame_qp - 12)) / 3.0)); |
| lambda_uv = pow(2.0, (((double)(chroma_qp - 12)) / 3.0)); |
| |
| /* modify the base lambda according to lambda modifier */ |
| lambda *= lambda_modifier; |
| lambda_uv *= lambda_uv_modifier; |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].u4_chroma_cost_weighing_factor = |
| (UWORD32)((lambda / lambda_uv) * (1 << CHROMA_COST_WEIGHING_FACTOR_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_type2_lambda_qf = |
| (LWORD64)(lambda * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i8_cl_ssd_type2_lambda_chroma_qf = |
| (LWORD64)(lambda_uv * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_sad_type2_lambda_qf = |
| (WORD32)(sqrt(lambda) * (1 << LAMBDA_Q_SHIFT)); |
| if(i4_use_const_lamda_modifier) |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_type2_lambda_qf = |
| (WORD32)((sqrt(lambda)) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_type2_lambda_qf = |
| (WORD32)(sqrt(lambda) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_type2_lambda_qf = |
| (WORD32)((sqrt(lambda)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| else |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_sad_type2_lambda_qf = |
| (WORD32)((sqrt(lambda) / 1.5) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_type2_lambda_qf = |
| (WORD32)(sqrt(lambda * 1.5) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_type2_lambda_qf = |
| (WORD32)((sqrt(lambda * 1.5)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| |
| break; |
| } |
| default: |
| { |
| /* Intended to be a barren wasteland! */ |
| ASSERT(0); |
| } |
| } |
| |
| /* Assign the final lambdas after up shifting to its q format */ |
| |
| /* closed loop ssd lambda is same as final lambda */ |
| |
| /* --- Initialized the lambda for SATD computations --- */ |
| if(i4_use_const_lamda_modifier) |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf = |
| (WORD32)(sqrt(lambda) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf = |
| (WORD32)((sqrt(lambda)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| else |
| { |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_cl_satd_lambda_qf = |
| (WORD32)(sqrt(lambda * 1.5) * (1 << LAMBDA_Q_SHIFT)); |
| |
| ps_cur_pic_ctxt->as_lambda_prms[i4_inst_id].i4_ol_satd_lambda_qf = |
| (WORD32)((sqrt(lambda * 1.5)) * (1 << (LAMBDA_Q_SHIFT))); |
| } |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_update_qp_L1_sad_based \endif |
| * |
| * \brief |
| * Function which recalculates qp in case of scene cut based on L1 satd/act |
| * |
| * \param[in] ps_enc_ctxt : encoder ctxt pointer |
| * \param[in] ps_cur_pic_ctxt : current pic ctxt |
| * \param[in] i4_cur_frame_qp : current pic QP |
| * \param[in] first_field : is first field flag |
| * \param[in] i4_temporal_lyr_id : Current picture layer id |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_update_qp_L1_sad_based( |
| enc_ctxt_t *ps_enc_ctxt, |
| ihevce_lap_enc_buf_t *ps_curr_inp, |
| ihevce_lap_enc_buf_t *ps_prev_inp, |
| pre_enc_me_ctxt_t *ps_curr_out, |
| WORD32 i4_is_last_thread) |
| { |
| WORD32 i4_l1_ht, i4_l1_wd; |
| ihevce_ed_blk_t *ps_ed_4x4 = ps_curr_out->ps_layer1_buf; |
| WORD32 best_satd_16x16; |
| //LWORD64 acc_satd = 0; |
| LWORD64 acc_sad = 0; /*SAD accumulated to compare with coarse me sad*/ |
| WORD32 i4_tot_4x4block_l1_x, i4_tot_4x4block_l1_y; |
| WORD32 i4_tot_ctb_l1_x, i4_tot_ctb_l1_y; |
| WORD32 i; |
| WORD32 i4_act_factor; |
| UWORD8 u1_cu_possible_qp; |
| WORD32 i4_q_scale_mod; |
| LWORD64 i8_best_satd_16x16; |
| LWORD64 i8_frame_satd_by_act_L1_accum; |
| LWORD64 i8_frame_acc_sadt_L1, i8_frame_acc_sadt_L1_squared; |
| WORD32 i4_new_frame_qp = 0, i4_qp_for_I_pic = 0; |
| LWORD64 pre_intra_satd_act_evaluated = 0; |
| ihevce_ed_ctb_l1_t *ps_ed_ctb_l1 = ps_curr_out->ps_ed_ctb_l1; |
| WORD32 i4_j; |
| double scale_factor_cmplx_change_detection; |
| WORD32 i4_cmplx_change_detection_thrsh; |
| long double ld_frame_avg_satd_L1; |
| |
| if(i4_is_last_thread) |
| { |
| ihevce_decomp_pre_intra_master_ctxt_t *ps_master_ctxt = |
| (ihevce_decomp_pre_intra_master_ctxt_t *) |
| ps_enc_ctxt->s_module_ctxt.pv_decomp_pre_intra_ctxt; |
| ihevce_decomp_pre_intra_ctxt_t *ps_ctxt = ps_master_ctxt->aps_decomp_pre_intra_thrd_ctxt[0]; |
| |
| i4_l1_wd = ps_ctxt->as_layers[1].i4_actual_wd; |
| i4_l1_ht = ps_ctxt->as_layers[1].i4_actual_ht; |
| |
| if((ps_curr_inp->s_lap_out.i4_quality_preset == IHEVCE_QUALITY_P6) && |
| (ps_curr_inp->s_lap_out.i4_temporal_lyr_id > TEMPORAL_LAYER_DISABLE)) |
| { |
| i8_frame_acc_sadt_L1 = -1; |
| } |
| else |
| { |
| /*the accumulation of intra satd and calculation of new qp happens for all thread |
| It must be made sure every thread returns same value of intra satd and qp*/ |
| i8_frame_acc_sadt_L1 = ihevce_decomp_pre_intra_get_frame_satd( |
| ps_enc_ctxt->s_module_ctxt.pv_decomp_pre_intra_ctxt, &i4_l1_wd, &i4_l1_ht); |
| } |
| |
| #if USE_SQRT_AVG_OF_SATD_SQR |
| if((ps_curr_inp->s_lap_out.i4_quality_preset == IHEVCE_QUALITY_P6) && |
| (ps_curr_inp->s_lap_out.i4_temporal_lyr_id > TEMPORAL_LAYER_DISABLE)) |
| { |
| i8_frame_acc_sadt_L1_squared = 0x7fffffff; |
| } |
| else |
| { |
| i8_frame_acc_sadt_L1_squared = ihevce_decomp_pre_intra_get_frame_satd_squared( |
| ps_enc_ctxt->s_module_ctxt.pv_decomp_pre_intra_ctxt, &i4_l1_wd, &i4_l1_ht); |
| } |
| #else |
| i8_frame_acc_sadt_L1_squared = i8_frame_acc_sadt_L1; |
| #endif |
| if((i4_l1_wd * i4_l1_ht) > (245760 /*640 * 384*/)) |
| { |
| scale_factor_cmplx_change_detection = |
| (double)0.12 * ((i4_l1_wd * i4_l1_ht) / (640.0 * 384.0)); |
| i4_cmplx_change_detection_thrsh = |
| (WORD32)(HME_HIGH_SAD_BLK_THRESH * (1 - scale_factor_cmplx_change_detection)); |
| } |
| else |
| { |
| scale_factor_cmplx_change_detection = |
| (double)0.12 * ((640.0 * 384.0) / (i4_l1_wd * i4_l1_ht)); |
| i4_cmplx_change_detection_thrsh = |
| (WORD32)(HME_HIGH_SAD_BLK_THRESH * (1 + scale_factor_cmplx_change_detection)); |
| } |
| i4_tot_4x4block_l1_x = |
| ((i4_l1_wd + ((MAX_CTB_SIZE >> 1) - 1)) & 0xFFFFFFE0) / |
| 4; //((i4_l1_wd + 31) & 0xFFFFFFE0)/4;//(i4_l1_wd + (i4_l1_wd % 32 )) / 4; |
| i4_tot_4x4block_l1_y = |
| ((i4_l1_ht + ((MAX_CTB_SIZE >> 1) - 1)) & 0xFFFFFFE0) / |
| 4; //((i4_l1_ht + 31) & 0xFFFFFFE0)/4;//(i4_l1_ht + (i4_l1_ht % 32 )) / 4; |
| ld_frame_avg_satd_L1 = |
| (WORD32)log( |
| 1 + (long double)i8_frame_acc_sadt_L1_squared / |
| ((long double)((i4_tot_4x4block_l1_x * i4_tot_4x4block_l1_y) >> 2))) / |
| log(2.0); |
| /* L1 satd accumalated for computing qp */ |
| i8_frame_satd_by_act_L1_accum = 0; |
| i4_tot_ctb_l1_x = |
| ((i4_l1_wd + ((MAX_CTB_SIZE >> 1) - 1)) & 0xFFFFFFE0) / (MAX_CTB_SIZE >> 1); |
| i4_tot_ctb_l1_y = |
| ((i4_l1_ht + ((MAX_CTB_SIZE >> 1) - 1)) & 0xFFFFFFE0) / (MAX_CTB_SIZE >> 1); |
| |
| for(i = 0; i < (i4_tot_ctb_l1_x * i4_tot_ctb_l1_y); i += 1) |
| { |
| for(i4_j = 0; i4_j < 16; i4_j++) |
| { |
| if(ps_ed_ctb_l1->i4_best_satd_8x8[i4_j] != -1) |
| { |
| ASSERT(ps_ed_ctb_l1->i4_best_satd_8x8[i4_j] >= 0); |
| ASSERT(ps_ed_ctb_l1->i4_best_sad_8x8_l1_ipe[i4_j] >= 0); |
| |
| if((ps_curr_inp->s_lap_out.i4_quality_preset == IHEVCE_QUALITY_P6) && |
| (ps_curr_inp->s_lap_out.i4_temporal_lyr_id > TEMPORAL_LAYER_DISABLE)) |
| { |
| best_satd_16x16 = 0; |
| } |
| else |
| { |
| best_satd_16x16 = ps_ed_ctb_l1->i4_best_satd_8x8[i4_j]; |
| } |
| |
| acc_sad += (WORD32)ps_ed_ctb_l1->i4_best_sad_8x8_l1_ipe[i4_j]; |
| //acc_satd += (WORD32)best_satd_16x16; |
| u1_cu_possible_qp = ihevce_cu_level_qp_mod( |
| 32, |
| best_satd_16x16, |
| ld_frame_avg_satd_L1, |
| REF_MOD_STRENGTH, // To be changed later |
| &i4_act_factor, |
| &i4_q_scale_mod, |
| &ps_enc_ctxt->s_rc_quant); |
| i8_best_satd_16x16 = best_satd_16x16 << QP_LEVEL_MOD_ACT_FACTOR; |
| |
| if((ps_curr_inp->s_lap_out.i4_quality_preset == IHEVCE_QUALITY_P6) && |
| (ps_curr_inp->s_lap_out.i4_temporal_lyr_id > TEMPORAL_LAYER_DISABLE)) |
| { |
| i4_act_factor = (1 << QP_LEVEL_MOD_ACT_FACTOR); |
| } |
| |
| if(0 != i4_act_factor) |
| { |
| i8_frame_satd_by_act_L1_accum += |
| ((WORD32)(i8_best_satd_16x16 / i4_act_factor)); |
| /*Accumulate SAD for those regions which will undergo evaluation in L0 stage*/ |
| if(ps_ed_4x4->intra_or_inter != 2) |
| pre_intra_satd_act_evaluated += |
| ((WORD32)(i8_best_satd_16x16 / i4_act_factor)); |
| } |
| } |
| ps_ed_4x4 += 4; |
| } |
| ps_ed_ctb_l1 += 1; |
| } |
| /** store the L1 satd in context struct |
| Note: this variable is common across all thread. it must be made sure all threads write same value*/ |
| if((ps_curr_inp->s_lap_out.i4_quality_preset == IHEVCE_QUALITY_P6) && |
| (ps_curr_inp->s_lap_out.i4_temporal_lyr_id > TEMPORAL_LAYER_DISABLE)) |
| { |
| i8_frame_satd_by_act_L1_accum = ps_prev_inp->s_rc_lap_out.i8_frame_satd_by_act_L1_accum; |
| ps_curr_inp->s_rc_lap_out.i8_frame_satd_by_act_L1_accum = i8_frame_satd_by_act_L1_accum; |
| ps_curr_inp->s_rc_lap_out.i8_satd_by_act_L1_accum_evaluated = -1; |
| } |
| else |
| { |
| ps_curr_inp->s_rc_lap_out.i8_frame_satd_by_act_L1_accum = i8_frame_satd_by_act_L1_accum; |
| ps_curr_inp->s_rc_lap_out.i8_satd_by_act_L1_accum_evaluated = |
| pre_intra_satd_act_evaluated; |
| } |
| |
| ps_curr_inp->s_rc_lap_out.i8_pre_intra_satd = i8_frame_acc_sadt_L1; |
| /*accumulate raw intra sad without subtracting non coded sad*/ |
| ps_curr_inp->s_rc_lap_out.i8_raw_pre_intra_sad = acc_sad; |
| } |
| /*update pre-enc qp using data from L1 to use better qp in L0 in case of cbr mode*/ |
| if(i4_is_last_thread) |
| { |
| /* acquire mutex lock for rate control calls */ |
| osal_mutex_lock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| { |
| LWORD64 i8_est_L0_satd_by_act; |
| WORD32 i4_cur_q_scale; |
| if(ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_rate_control_mode != CONST_QP) |
| { |
| /*RCTODO :This needs to be reviewed in the context of 10/12 bit encoding as the Qp seems to be sub-optimal*/ |
| if(ps_enc_ctxt->ps_stat_prms->s_pass_prms.i4_pass != 2) |
| i4_cur_q_scale = |
| ps_enc_ctxt->s_rc_quant.pi4_qp_to_qscale |
| [ps_curr_out->i4_curr_frm_qp]; // + ps_enc_ctxt->s_rc_quant.i1_qp_offset]; |
| else |
| i4_cur_q_scale = ps_enc_ctxt->s_rc_quant |
| .pi4_qp_to_qscale[MAX(ps_curr_out->i4_curr_frm_qp, 0)]; |
| } |
| else |
| i4_cur_q_scale = |
| ps_enc_ctxt->s_rc_quant.pi4_qp_to_qscale |
| [ps_curr_out->i4_curr_frm_qp + ps_enc_ctxt->s_rc_quant.i1_qp_offset]; |
| |
| i4_cur_q_scale = (i4_cur_q_scale + (1 << (QSCALE_Q_FAC_3 - 1))) >> QSCALE_Q_FAC_3; |
| |
| i8_est_L0_satd_by_act = ihevce_get_L0_satd_based_on_L1( |
| i8_frame_satd_by_act_L1_accum, |
| ps_curr_inp->s_rc_lap_out.i4_num_pels_in_frame_considered, |
| i4_cur_q_scale); |
| /*HEVC_RC query rate control for qp*/ |
| if(ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_rate_control_mode != 3) |
| { |
| i4_new_frame_qp = ihevce_get_L0_est_satd_based_scd_qp( |
| ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], |
| &ps_curr_inp->s_rc_lap_out, |
| i8_est_L0_satd_by_act, |
| 8.00); |
| } |
| else |
| i4_new_frame_qp = ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms |
| .as_tgt_params[ps_enc_ctxt->i4_resolution_id] |
| .ai4_frame_qp[0]; |
| i4_new_frame_qp = CLIP3(i4_new_frame_qp, 1, 51); |
| i4_qp_for_I_pic = CLIP3(i4_qp_for_I_pic, 1, 51); |
| ps_curr_inp->s_rc_lap_out.i4_L1_qp = i4_new_frame_qp; |
| /*I frame qp = qp-3 due to effect of lambda modifier*/ |
| i4_qp_for_I_pic = i4_new_frame_qp - 3; |
| |
| /*use new qp get possible qp even for inter pictures assuming default offset*/ |
| if(ps_curr_inp->s_lap_out.i4_pic_type != IV_IDR_FRAME && |
| ps_curr_inp->s_lap_out.i4_pic_type != IV_I_FRAME) |
| { |
| i4_new_frame_qp += ps_curr_inp->s_lap_out.i4_temporal_lyr_id + 1; |
| } |
| |
| /*accumulate the L1 ME sad using skip sad value based on qp*/ |
| /*accumulate this only for last thread as it ll be guranteed that L1 ME sad is completely populated*/ |
| /*The lambda modifier in encoder is tuned in such a way that the qp offsets according to lambda modifer are as follows |
| Note: These qp offset only account for lambda modifier, Hence this should be applied over qp offset that is already there due to picture type |
| relative lambda scale(these lambda diff are mapped into qp difference which is applied over and obove the qp offset) |
| Qi = Iqp 1 |
| Qp = Iqp 1 |
| Qb = Iqp + 1.55 1.48 |
| Qb1 = Iqp + 3.1 2.05 |
| Qb2 = Iqp + 3.1 2.05*/ |
| |
| /*ihevce_compute_offsets_from_rc(ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0],ai4_offsets,&ps_curr_inp->s_lap_out);*/ |
| |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_I_FRAME || |
| ps_curr_inp->s_lap_out.i4_pic_type == IV_IDR_FRAME) |
| { |
| i4_new_frame_qp = i4_new_frame_qp - 3; |
| } |
| else if(ps_curr_inp->s_lap_out.i4_pic_type == IV_P_FRAME) |
| { |
| i4_new_frame_qp = i4_new_frame_qp - 2; |
| } |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_B_FRAME && |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id == 1) |
| { |
| i4_new_frame_qp = i4_new_frame_qp + 2; |
| } |
| else if( |
| ps_curr_inp->s_lap_out.i4_pic_type == IV_B_FRAME && |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id == 2) |
| { |
| i4_new_frame_qp = i4_new_frame_qp + 6; |
| } |
| else if( |
| ps_curr_inp->s_lap_out.i4_pic_type == IV_B_FRAME && |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id == 3) |
| { |
| i4_new_frame_qp = i4_new_frame_qp + 7; |
| } |
| |
| i4_new_frame_qp = CLIP3(i4_new_frame_qp, 1, 51); |
| i4_qp_for_I_pic = CLIP3(i4_qp_for_I_pic, 1, 51); |
| |
| { |
| calc_l1_level_hme_intra_sad_different_qp( |
| ps_enc_ctxt, ps_curr_out, ps_curr_inp, i4_tot_ctb_l1_x, i4_tot_ctb_l1_y); |
| |
| /** frame accumulated SAD over entire frame after accounting for dead zone SAD, this is least of intra or inter*/ |
| /*ihevce_accum_hme_sad_subgop_rc(ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0],&ps_curr_inp->s_lap_out); */ |
| ihevce_rc_register_L1_analysis_data( |
| ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], |
| &ps_curr_inp->s_rc_lap_out, |
| i8_est_L0_satd_by_act, |
| ps_curr_inp->s_rc_lap_out.ai8_pre_intra_sad |
| [i4_new_frame_qp], //since the sad passed will be used to calc complexity it should be non coded sad subtracted sad |
| ps_curr_inp->s_rc_lap_out.ai8_frame_acc_coarse_me_sad[i4_new_frame_qp]); |
| |
| ihevce_coarse_me_get_rc_param( |
| ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt, |
| &ps_curr_out->i8_acc_frame_coarse_me_cost, |
| &ps_curr_out->i8_acc_frame_coarse_me_sad, |
| &ps_curr_out->i8_acc_num_blks_high_sad, |
| &ps_curr_out->i8_total_blks, |
| ps_curr_inp->s_lap_out.i4_is_prev_pic_in_Tid0_same_scene); |
| |
| if(ps_curr_out->i8_total_blks) |
| { |
| ps_curr_out->i4_complexity_percentage = (WORD32)( |
| (ps_curr_out->i8_acc_num_blks_high_sad * 100) / |
| (ps_curr_out->i8_total_blks)); |
| } |
| /*not for Const QP mode*/ |
| if(ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_rate_control_mode != 3) |
| { |
| if(ps_curr_inp->s_lap_out.i4_is_prev_pic_in_Tid0_same_scene && |
| ps_curr_out->i8_total_blks && |
| (((float)(ps_curr_out->i8_acc_num_blks_high_sad * 100) / |
| (ps_curr_out->i8_total_blks)) > (i4_cmplx_change_detection_thrsh))) |
| { |
| ps_curr_out->i4_is_high_complex_region = 1; |
| } |
| else |
| { |
| ps_curr_out->i4_is_high_complex_region = 0; |
| } |
| } |
| ps_curr_inp->s_rc_lap_out.i8_frame_acc_coarse_me_cost = |
| ps_curr_out->i8_acc_frame_coarse_me_cost; |
| /*check for I only reset case and Non I SCD*/ |
| ihevce_rc_check_non_lap_scd( |
| ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], &ps_curr_inp->s_rc_lap_out); |
| } |
| } |
| /* release mutex lock after rate control calls */ |
| osal_mutex_unlock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| } |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_frame_init \endif |
| * |
| * \brief |
| * Pre encode Frame processing slave thread entry point function |
| * |
| * \param[in] Frame processing thread context pointer |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_frame_init( |
| enc_ctxt_t *ps_enc_ctxt, |
| pre_enc_me_ctxt_t *ps_curr_inp_prms, |
| me_enc_rdopt_ctxt_t *ps_cur_out_me_prms, |
| WORD32 i4_cur_frame_qp, |
| WORD32 i4_me_frm_id, |
| WORD32 i4_thrd_id) |
| { |
| ihevce_lap_enc_buf_t *ps_curr_inp; |
| WORD32 first_field = 1; |
| me_master_ctxt_t *ps_master_ctxt; |
| |
| (void)i4_thrd_id; |
| (void)ps_cur_out_me_prms; |
| ps_curr_inp = ps_curr_inp_prms->ps_curr_inp; |
| |
| ps_master_ctxt = (me_master_ctxt_t *)ps_enc_ctxt->s_module_ctxt.pv_me_ctxt; |
| |
| /* get frame level lambda params */ |
| ihevce_get_frame_lambda_prms( |
| ps_enc_ctxt, |
| ps_curr_inp_prms, |
| i4_cur_frame_qp, |
| first_field, |
| ps_curr_inp->s_lap_out.i4_is_ref_pic, |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id, |
| ps_curr_inp->s_lap_out.f_i_pic_lamda_modifier, |
| 0, |
| ENC_LAMBDA_TYPE); |
| |
| if(1 == ps_curr_inp_prms->i4_frm_proc_valid_flag) |
| { |
| UWORD8 i1_cu_qp_delta_enabled_flag = |
| ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_cu_level_rc; |
| |
| /* picture level init of ME */ |
| ihevce_me_frame_init( |
| ps_enc_ctxt->s_module_ctxt.pv_me_ctxt, |
| ps_cur_out_me_prms, |
| ps_enc_ctxt->ps_stat_prms, |
| &ps_enc_ctxt->s_frm_ctb_prms, |
| &ps_curr_inp_prms->as_lambda_prms[0], |
| ps_enc_ctxt->i4_num_ref_l0, |
| ps_enc_ctxt->i4_num_ref_l1, |
| ps_enc_ctxt->i4_num_ref_l0_active, |
| ps_enc_ctxt->i4_num_ref_l1_active, |
| &ps_cur_out_me_prms->aps_ref_list[0][LIST_0][0], |
| &ps_cur_out_me_prms->aps_ref_list[0][LIST_1][0], |
| ps_cur_out_me_prms->aps_ref_list[0], |
| &ps_enc_ctxt->s_func_selector, |
| ps_curr_inp, |
| ps_curr_inp_prms->pv_me_lyr_ctxt, |
| i4_me_frm_id, |
| i4_thrd_id, |
| i4_cur_frame_qp, |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id, |
| i1_cu_qp_delta_enabled_flag, |
| ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id]->pv_dep_mngr_encloop_dep_me); |
| |
| /* -------------------------------------------------------- */ |
| /* Preparing Job Queue for ME and each instance of enc_loop */ |
| /* -------------------------------------------------------- */ |
| ihevce_prepare_job_queue(ps_enc_ctxt, ps_curr_inp, i4_me_frm_id); |
| |
| /* Dep. Mngr : Reset the num ctb processed in every row for ENC sync */ |
| ihevce_dmgr_rst_row_row_sync( |
| ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id]->pv_dep_mngr_encloop_dep_me); |
| } |
| } |
| |
| /**************************************************************************** |
| Function Name : ihevce_rc_close |
| Description : closing the Rate control by passing the stored data in to the stat file for 2 pass encoding. |
| Inputs : |
| Globals : |
| Processing : |
| Outputs : |
| Returns : |
| Issues : |
| Revision History: |
| DD MM YYYY Author(s) Changes (Describe the changes made) |
| *****************************************************************************/ |
| |
| void ihevce_rc_close( |
| enc_ctxt_t *ps_enc_ctxt, |
| WORD32 i4_enc_frm_id_rc, |
| WORD32 i4_store_retrive, |
| WORD32 i4_update_cnt, |
| WORD32 i4_bit_rate_idx) |
| { |
| rc_bits_sad_t s_rc_frame_stat; |
| WORD32 out_buf_id; |
| WORD32 i4_pic_type, k; |
| WORD32 cur_qp; |
| ihevce_lap_output_params_t s_lap_out; |
| rc_lap_out_params_t s_rc_lap_out; |
| |
| for(k = 0; k < i4_update_cnt; k++) //ELP_RC |
| { |
| ihevce_rc_store_retrive_update_info( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i4_bit_rate_idx], |
| &s_rc_frame_stat, |
| i4_enc_frm_id_rc, |
| i4_bit_rate_idx, |
| 2, |
| &out_buf_id, |
| &i4_pic_type, |
| &cur_qp, |
| (void *)&s_lap_out, |
| (void *)&s_rc_lap_out); |
| |
| ihevce_rc_update_pic_info( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i4_bit_rate_idx], |
| (s_rc_frame_stat.u4_total_texture_bits + |
| s_rc_frame_stat.u4_total_header_bits), //pass total bits |
| s_rc_frame_stat.u4_total_header_bits, |
| s_rc_frame_stat.u4_total_sad, |
| s_rc_frame_stat.u4_total_intra_sad, |
| (IV_PICTURE_CODING_TYPE_T)i4_pic_type, |
| cur_qp, |
| 0, |
| s_rc_frame_stat.i4_qp_normalized_8x8_cu_sum, |
| s_rc_frame_stat.i4_8x8_cu_sum, |
| s_rc_frame_stat.i8_sad_by_qscale, |
| &s_lap_out, |
| &s_rc_lap_out, |
| out_buf_id, |
| s_rc_frame_stat.u4_open_loop_intra_sad, |
| s_rc_frame_stat.i8_total_ssd_frame, |
| i4_enc_frm_id_rc); //ps_curr_out->i4_inp_timestamp_low) |
| i4_enc_frm_id_rc++; |
| i4_enc_frm_id_rc = (i4_enc_frm_id_rc % ps_enc_ctxt->i4_max_fr_enc_loop_parallel_rc); |
| } |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_enc_frm_proc_slave_thrd \endif |
| * |
| * \brief |
| * Enocde Frame processing slave thread entry point function |
| * |
| * \param[in] Frame processing thread context pointer |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| WORD32 ihevce_enc_frm_proc_slave_thrd(void *pv_frm_proc_thrd_ctxt) |
| { |
| frm_proc_thrd_ctxt_t *ps_thrd_ctxt; |
| enc_ctxt_t *ps_enc_ctxt; |
| WORD32 i4_me_end_flag, i4_enc_end_flag; |
| WORD32 i4_thrd_id; |
| ihevce_hle_ctxt_t *ps_hle_ctxt; |
| WORD32 i4_num_bitrates; //number of bit-rates instances running |
| WORD32 i; //ctr |
| void *pv_dep_mngr_prev_frame_me_done; |
| void *pv_dep_mngr_prev_frame_done; |
| WORD32 i4_resolution_id; |
| WORD32 i4_enc_frm_id_rc = 0; |
| WORD32 i4_enc_frm_id = 0; |
| WORD32 i4_me_frm_id = 0; |
| |
| ps_thrd_ctxt = (frm_proc_thrd_ctxt_t *)pv_frm_proc_thrd_ctxt; |
| ps_hle_ctxt = ps_thrd_ctxt->ps_hle_ctxt; |
| ps_enc_ctxt = (enc_ctxt_t *)ps_thrd_ctxt->pv_enc_ctxt; /*Changed for mres*/ |
| i4_thrd_id = ps_thrd_ctxt->i4_thrd_id; |
| i4_me_end_flag = 0; |
| i4_enc_end_flag = 0; |
| i4_num_bitrates = ps_enc_ctxt->i4_num_bitrates; |
| i4_resolution_id = ps_enc_ctxt->i4_resolution_id; |
| |
| /*pv_dep_mngr_prev_frame_me_done = |
| ps_enc_ctxt->s_multi_thrd.pv_dep_mngr_prev_frame_me_done;*/ |
| |
| while((0 == i4_me_end_flag) && (0 == i4_enc_end_flag)) |
| { |
| WORD32 result; |
| WORD32 ai4_in_buf_id[MAX_NUM_ME_PARALLEL]; |
| me_enc_rdopt_ctxt_t *ps_curr_out_me; |
| |
| if(1 == ps_enc_ctxt->s_multi_thrd.i4_num_me_frm_pllel) |
| { |
| pv_dep_mngr_prev_frame_me_done = |
| ps_enc_ctxt->s_multi_thrd.apv_dep_mngr_prev_frame_me_done[0]; |
| } |
| else |
| { |
| pv_dep_mngr_prev_frame_me_done = |
| ps_enc_ctxt->s_multi_thrd.apv_dep_mngr_prev_frame_me_done[i4_me_frm_id]; |
| } |
| |
| /* Wait till the previous frame ME is completly done*/ |
| { |
| ihevce_dmgr_chk_frm_frm_sync(pv_dep_mngr_prev_frame_me_done, ps_thrd_ctxt->i4_thrd_id); |
| } |
| |
| /****** Lock the critical section ******/ |
| if(NULL != ps_enc_ctxt->s_multi_thrd.apv_mutex_handle[i4_me_frm_id]) |
| { |
| result = osal_mutex_lock(ps_enc_ctxt->s_multi_thrd.apv_mutex_handle[i4_me_frm_id]); |
| |
| if(OSAL_SUCCESS != result) |
| return 0; |
| } |
| |
| { |
| /************************************/ |
| /****** ENTER CRITICAL SECTION ******/ |
| /************************************/ |
| |
| /* First slave getting the mutex lock will act as master and does ME init |
| * of current frame and other slaves skip it |
| */ |
| if(ps_enc_ctxt->s_multi_thrd.ai4_me_master_done_flag[i4_me_frm_id] == 0) |
| { |
| WORD32 i4_ref_cur_qp; //current frame Qp for reference bit-rate instance |
| ihevce_lap_enc_buf_t *ps_curr_inp = NULL; |
| |
| if(0 == i4_me_end_flag) |
| { |
| /* ------- get the input prms buffer from pre encode que ------------ */ |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] = |
| (pre_enc_me_ctxt_t *)ihevce_q_get_filled_buff( |
| (void *)ps_enc_ctxt, |
| IHEVCE_PRE_ENC_ME_Q, |
| &ai4_in_buf_id[i4_me_frm_id], |
| BUFF_QUE_BLOCKING_MODE); |
| /*always buffer must be available*/ |
| ASSERT(ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] != NULL); |
| |
| ps_enc_ctxt->s_multi_thrd.is_in_buf_freed[i4_enc_frm_id] = 0; |
| |
| /* ------- get the input prms buffer from L0 IPE queue ------------ */ |
| ps_enc_ctxt->s_multi_thrd.aps_cur_L0_ipe_inp_prms[i4_me_frm_id] = |
| (pre_enc_L0_ipe_encloop_ctxt_t *)ihevce_q_get_filled_buff( |
| (void *)ps_enc_ctxt, |
| IHEVCE_L0_IPE_ENC_Q, |
| &ps_enc_ctxt->s_multi_thrd.ai4_in_frm_l0_ipe_id[i4_me_frm_id], |
| BUFF_QUE_BLOCKING_MODE); |
| |
| /*always buffer must be available*/ |
| ASSERT(ps_enc_ctxt->s_multi_thrd.aps_cur_L0_ipe_inp_prms[i4_me_frm_id] != NULL); |
| |
| /* ------- get the free buffer from me_enc que ------------ */ |
| ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id] = |
| (me_enc_rdopt_ctxt_t *)ihevce_q_get_free_buff( |
| ps_enc_ctxt, |
| IHEVCE_ME_ENC_RDOPT_Q, |
| &ps_enc_ctxt->s_multi_thrd.ai4_me_out_buf_id[i4_me_frm_id], |
| BUFF_QUE_BLOCKING_MODE); |
| |
| /*always buffer must be available*/ |
| ASSERT(ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id] != NULL); |
| } |
| if(NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] && |
| NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id] && |
| NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_L0_ipe_inp_prms[i4_me_frm_id]) |
| { |
| ps_curr_inp = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]->ps_curr_inp; |
| |
| ps_curr_out_me = ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id]; |
| |
| ps_curr_out_me->ps_curr_inp_from_l0_ipe_prms = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_L0_ipe_inp_prms[i4_me_frm_id]; |
| |
| /*initialization of curr out me*/ |
| ps_curr_out_me->ps_curr_inp_from_me_prms = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]; |
| |
| ps_curr_out_me->curr_inp_from_me_buf_id = ai4_in_buf_id[i4_me_frm_id]; |
| |
| ps_curr_out_me->i4_buf_id = |
| ps_enc_ctxt->s_multi_thrd.ai4_me_out_buf_id[i4_me_frm_id]; |
| |
| ps_curr_out_me->ps_curr_inp = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]->ps_curr_inp; |
| |
| ps_curr_out_me->curr_inp_buf_id = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]->curr_inp_buf_id; |
| |
| ps_curr_out_me->curr_inp_from_l0_ipe_buf_id = |
| ps_enc_ctxt->s_multi_thrd.ai4_in_frm_l0_ipe_id[i4_me_frm_id]; |
| |
| ps_curr_out_me->i4_frm_proc_valid_flag = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] |
| ->i4_frm_proc_valid_flag; |
| |
| ps_curr_out_me->i4_end_flag = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]->i4_end_flag; |
| |
| /* set the parameters for sync b/w entropy thread */ |
| |
| ps_enc_ctxt->s_multi_thrd.me_end_flag = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]->i4_end_flag; |
| |
| /* do the processing if input frm data is valid */ |
| if(1 == ps_curr_inp->s_input_buf.i4_inp_frm_data_valid_flag) |
| { |
| /* slice header will be populated in pre-enocde stage */ |
| memcpy( |
| &ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id] |
| ->s_slice_hdr, |
| &ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] |
| ->s_slice_hdr, |
| sizeof(slice_header_t)); |
| |
| if(ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] |
| ->i4_frm_proc_valid_flag) |
| { |
| WORD32 ctr; |
| recon_pic_buf_t *ps_frm_recon; |
| for(i = 0; i < i4_num_bitrates; i++) |
| { |
| /* run a loop to free the non used reference pics */ |
| /* This is done here because its assured that recon buf |
| * between app and encode loop is set as produced |
| */ |
| { |
| WORD32 i4_free_id; |
| i4_free_id = ihevce_find_free_indx( |
| ps_enc_ctxt->pps_recon_buf_q[i], |
| ps_enc_ctxt->ai4_num_buf_recon_q[i]); |
| |
| if(i4_free_id != -1) |
| { |
| ps_enc_ctxt->pps_recon_buf_q[i][i4_free_id]->i4_is_free = 1; |
| ps_enc_ctxt->pps_recon_buf_q[i][i4_free_id]->i4_poc = -1; |
| } |
| } |
| |
| ps_frm_recon = NULL; |
| for(ctr = 0; ctr < ps_enc_ctxt->ai4_num_buf_recon_q[i]; ctr++) |
| { |
| if(ps_enc_ctxt->pps_recon_buf_q[i][ctr]->i4_is_free) |
| { |
| ps_frm_recon = ps_enc_ctxt->pps_recon_buf_q[i][ctr]; |
| break; |
| } |
| } |
| ASSERT(ps_frm_recon != NULL); |
| |
| ps_frm_recon->i4_is_free = 0; |
| ps_frm_recon->i4_non_ref_free_flag = 0; |
| ps_frm_recon->i4_topfield_first = |
| ps_curr_inp->s_input_buf.i4_topfield_first; |
| ps_frm_recon->i4_poc = ps_curr_inp->s_lap_out.i4_poc; |
| ps_frm_recon->i4_pic_type = ps_curr_inp->s_lap_out.i4_pic_type; |
| ps_frm_recon->i4_display_num = |
| ps_curr_inp->s_lap_out.i4_display_num; |
| ps_frm_recon->i4_idr_gop_num = |
| ps_curr_inp->s_lap_out.i4_idr_gop_num; |
| ps_frm_recon->i4_bottom_field = |
| ps_curr_inp->s_input_buf.i4_bottom_field; |
| ps_frm_recon->i4_is_reference = |
| ps_curr_inp->s_lap_out.i4_is_ref_pic; |
| |
| { |
| WORD32 sei_hash_enabled = |
| (ps_enc_ctxt->ps_stat_prms->s_out_strm_prms |
| .i4_sei_enable_flag == 1) && |
| (ps_enc_ctxt->ps_stat_prms->s_out_strm_prms |
| .i4_decoded_pic_hash_sei_flag != 0); |
| |
| /* Deblock a picture for all reference frames unconditionally. */ |
| /* Deblock non ref if psnr compute or save recon is enabled */ |
| ps_frm_recon->i4_deblk_pad_hpel_cur_pic = |
| ps_frm_recon->i4_is_reference || |
| (ps_enc_ctxt->ps_stat_prms->i4_save_recon) || |
| (1 == sei_hash_enabled); |
| } |
| |
| ps_frm_recon->s_yuv_buf_desc.i4_y_ht = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_ht; |
| ps_frm_recon->s_yuv_buf_desc.i4_uv_ht = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_ht >> |
| ((ps_enc_ctxt->s_runtime_src_prms.i4_chr_format == |
| IV_YUV_422SP_UV) |
| ? 0 |
| : 1); |
| ps_frm_recon->s_yuv_buf_desc.i4_y_wd = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd; |
| ps_frm_recon->s_yuv_buf_desc.i4_uv_wd = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd; |
| ps_frm_recon->s_yuv_buf_desc.i4_y_strd = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd + |
| (PAD_HORZ << 1); |
| ps_frm_recon->s_yuv_buf_desc.i4_uv_strd = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd + |
| (PAD_HORZ << 1); |
| |
| /* reset the row_frm dep mngr for ME reverse sync for reference bitrate */ |
| if(i == 0) |
| { |
| ihevce_dmgr_map_rst_sync(ps_frm_recon->pv_dep_mngr_recon); |
| } |
| |
| ps_enc_ctxt->s_multi_thrd.ps_frm_recon[i4_enc_frm_id][i] = |
| ps_frm_recon; |
| } |
| } |
| /* Reference buffer management and reference list creation */ |
| /* This needs to be created for each bit-rate since the reconstructed output is |
| different for all bit-rates. ME uses only 0th instnace ref list */ |
| for(i = i4_num_bitrates - 1; i >= 0; i--) |
| { |
| ihevce_manage_ref_pics( |
| ps_enc_ctxt, |
| ps_curr_inp, |
| &ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id] |
| ->s_slice_hdr, |
| i4_me_frm_id, |
| i4_thrd_id, |
| i); /* bitrate instance ID */ |
| } |
| /*query of qp to be moved just before encoding starts*/ |
| i4_ref_cur_qp = ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] |
| ->i4_curr_frm_qp; |
| /* The Qp populated in Pre enc stage needs to overwritten with Qp |
| queried from rate control*/ |
| } |
| else |
| { |
| i4_ref_cur_qp = 0; |
| } |
| |
| /* call the core encoding loop */ |
| ihevce_frame_init( |
| ps_enc_ctxt, |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id], |
| ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id], |
| i4_ref_cur_qp, |
| i4_me_frm_id, |
| i4_thrd_id); |
| } |
| |
| ps_enc_ctxt->s_multi_thrd.ai4_me_master_done_flag[i4_me_frm_id] = 1; |
| } |
| } |
| |
| /************************************/ |
| /****** EXIT CRITICAL SECTION ******/ |
| /************************************/ |
| |
| /****** Unlock the critical section ******/ |
| if(NULL != ps_enc_ctxt->s_multi_thrd.apv_mutex_handle[i4_me_frm_id]) |
| { |
| result = osal_mutex_unlock(ps_enc_ctxt->s_multi_thrd.apv_mutex_handle[i4_me_frm_id]); |
| if(OSAL_SUCCESS != result) |
| return 0; |
| } |
| |
| if((1 == ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.i4_mres_single_out) && |
| (1 == ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] |
| ->ps_curr_inp->s_lap_out.i4_first_frm_new_res)) |
| { |
| /* Reset the enc frame rc id whenver change in resolution happens */ |
| i4_enc_frm_id_rc = 0; |
| } |
| |
| /*update end flag for each thread */ |
| i4_me_end_flag = ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]->i4_end_flag; |
| if(NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] && |
| NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id] && |
| NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_L0_ipe_inp_prms[i4_me_frm_id]) |
| { |
| pre_enc_me_ctxt_t *ps_curr_inp_prms; |
| pre_enc_L0_ipe_encloop_ctxt_t *ps_curr_L0_IPE_inp_prms; |
| ihevce_lap_enc_buf_t *ps_curr_inp; |
| |
| /* get the current buffer pointer */ |
| ps_curr_inp_prms = ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]; |
| ps_curr_L0_IPE_inp_prms = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_L0_ipe_inp_prms[i4_me_frm_id]; |
| ps_curr_inp = ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]->ps_curr_inp; |
| |
| /* -------------------------------------------------- */ |
| /* Motion estimation (enc layer) of entire frame */ |
| /* -------------------------------------------------- */ |
| if((i4_me_end_flag == 0) && |
| (1 == |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]->i4_frm_proc_valid_flag)) |
| { |
| /* Init i4_is_prev_frame_reference for the next P-frame */ |
| me_master_ctxt_t *ps_master_ctxt = |
| (me_master_ctxt_t *)ps_enc_ctxt->s_module_ctxt.pv_me_ctxt; |
| |
| /* get the current thread ctxt pointer */ |
| me_ctxt_t *ps_ctxt = ps_master_ctxt->aps_me_ctxt[i4_thrd_id]; |
| |
| me_frm_ctxt_t *ps_frm_ctxt = ps_ctxt->aps_me_frm_prms[i4_me_frm_id]; |
| |
| if(ISLICE != ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] |
| ->s_slice_hdr.i1_slice_type) |
| { |
| ihevce_me_process( |
| ps_enc_ctxt->s_module_ctxt.pv_me_ctxt, |
| ps_curr_inp, |
| ps_curr_inp_prms->ps_ctb_analyse, |
| ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id], |
| ps_curr_inp_prms->plf_intra_8x8_cost, |
| ps_curr_L0_IPE_inp_prms->ps_ipe_analyse_ctb, |
| ps_curr_L0_IPE_inp_prms, |
| ps_curr_inp_prms->pv_me_lyr_ctxt, |
| &ps_enc_ctxt->s_multi_thrd, |
| ((ps_enc_ctxt->s_multi_thrd.i4_num_me_frm_pllel == 1) ? 0 : 1), |
| i4_thrd_id, |
| i4_me_frm_id); |
| } |
| else |
| |
| { |
| /* Init i4_is_prev_frame_reference for the next P-frame */ |
| me_master_ctxt_t *ps_master_ctxt = |
| (me_master_ctxt_t *)ps_enc_ctxt->s_module_ctxt.pv_me_ctxt; |
| |
| /* get the current thread ctxt pointer */ |
| me_ctxt_t *ps_ctxt = ps_master_ctxt->aps_me_ctxt[i4_thrd_id]; |
| |
| me_frm_ctxt_t *ps_frm_ctxt = ps_ctxt->aps_me_frm_prms[i4_me_frm_id]; |
| |
| multi_thrd_ctxt_t *ps_multi_thrd_ctxt = &ps_enc_ctxt->s_multi_thrd; |
| |
| if(ps_enc_ctxt->s_multi_thrd.i4_num_me_frm_pllel != 1) |
| { |
| ps_frm_ctxt->i4_is_prev_frame_reference = 0; |
| } |
| else |
| { |
| ps_frm_ctxt->i4_is_prev_frame_reference = |
| ps_multi_thrd_ctxt->aps_cur_inp_me_prms[i4_me_frm_id] |
| ->ps_curr_inp->s_lap_out.i4_is_ref_pic; |
| } |
| } |
| } |
| } |
| /************************************/ |
| /****** ENTER CRITICAL SECTION *****/ |
| /************************************/ |
| { |
| WORD32 result_frame_init; |
| void *pv_mutex_handle_frame_init; |
| |
| /* Create mutex for locking non-reentrant sections */ |
| pv_mutex_handle_frame_init = |
| ps_enc_ctxt->s_multi_thrd.apv_mutex_handle_me_end[i4_me_frm_id]; |
| |
| /****** Lock the critical section ******/ |
| if(NULL != pv_mutex_handle_frame_init) |
| { |
| result_frame_init = osal_mutex_lock(pv_mutex_handle_frame_init); |
| |
| if(OSAL_SUCCESS != result_frame_init) |
| return 0; |
| } |
| } |
| |
| if(0 == ps_enc_ctxt->s_multi_thrd.ai4_me_enc_buff_prod_flag[i4_me_frm_id]) |
| { |
| /* ------- set buffer produced from me_enc que ------------ */ |
| ihevce_q_set_buff_prod( |
| ps_enc_ctxt, |
| IHEVCE_ME_ENC_RDOPT_Q, |
| ps_enc_ctxt->s_multi_thrd.ai4_me_out_buf_id[i4_me_frm_id]); |
| |
| ps_enc_ctxt->s_multi_thrd.ai4_me_enc_buff_prod_flag[i4_me_frm_id] = 1; |
| } |
| if(NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] && |
| NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id]) |
| { |
| ihevce_lap_enc_buf_t *ps_curr_inp; |
| |
| WORD32 first_field = 1; |
| |
| /* Increment the counter to keep track of no of threads exiting the current mutex*/ |
| ps_enc_ctxt->s_multi_thrd.me_num_thrds_exited[i4_me_frm_id]++; |
| |
| ps_curr_inp = ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id]->ps_curr_inp; |
| /* Last slave thread will reset the master done frame init flag and set the prev |
| * frame me done flag for curr frame |
| */ |
| if(ps_enc_ctxt->s_multi_thrd.me_num_thrds_exited[i4_me_frm_id] == |
| ps_enc_ctxt->s_multi_thrd.i4_num_enc_proc_thrds) |
| { |
| ps_enc_ctxt->s_multi_thrd.me_num_thrds_exited[i4_me_frm_id] = 0; |
| |
| ps_enc_ctxt->s_multi_thrd.ai4_me_master_done_flag[i4_me_frm_id] = 0; |
| |
| /* Update Dyn. Vert. Search prms for P Pic. */ |
| if(IV_P_FRAME == ps_curr_inp->s_lap_out.i4_pic_type) |
| { |
| WORD32 i4_idx_dvsr_p = ps_enc_ctxt->s_multi_thrd.i4_idx_dvsr_p; |
| /* Sanity Check */ |
| ASSERT(ps_curr_inp->s_lap_out.i4_pic_type < IV_IP_FRAME); |
| |
| /* Frame END processing for Dynamic Vertival Search */ |
| ihevce_l0_me_frame_end( |
| ps_enc_ctxt->s_module_ctxt.pv_me_ctxt, |
| i4_idx_dvsr_p, |
| ps_curr_inp->s_lap_out.i4_display_num, |
| i4_me_frm_id); |
| |
| ps_enc_ctxt->s_multi_thrd.i4_idx_dvsr_p++; |
| if(ps_enc_ctxt->s_multi_thrd.i4_idx_dvsr_p == NUM_SG_INTERLEAVED) |
| { |
| ps_enc_ctxt->s_multi_thrd.i4_idx_dvsr_p = 0; |
| } |
| } |
| if(1 == ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] |
| ->i4_frm_proc_valid_flag) |
| { |
| /* Init i4_is_prev_frame_reference for the next P-frame */ |
| me_master_ctxt_t *ps_master_ctxt = |
| (me_master_ctxt_t *)ps_enc_ctxt->s_module_ctxt.pv_me_ctxt; |
| |
| /* get the current thread ctxt pointer */ |
| me_ctxt_t *ps_ctxt = ps_master_ctxt->aps_me_ctxt[i4_thrd_id]; |
| |
| me_frm_ctxt_t *ps_frm_ctxt = ps_ctxt->aps_me_frm_prms[i4_me_frm_id]; |
| |
| ps_frm_ctxt->ps_curr_descr->aps_layers[0]->i4_non_ref_free = 1; |
| } |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_me_prms[i4_me_frm_id] = NULL; |
| ps_enc_ctxt->s_multi_thrd.aps_cur_out_me_prms[i4_me_frm_id] = NULL; |
| ps_enc_ctxt->s_multi_thrd.aps_cur_L0_ipe_inp_prms[i4_me_frm_id] = NULL; |
| ps_enc_ctxt->s_multi_thrd.ai4_me_enc_buff_prod_flag[i4_me_frm_id] = 0; |
| ps_enc_ctxt->s_multi_thrd.ai4_me_master_done_flag[i4_me_frm_id] = 0; |
| |
| /* Set me processing done for curr frame in the dependency manager */ |
| ihevce_dmgr_update_frm_frm_sync(pv_dep_mngr_prev_frame_me_done); |
| } |
| } |
| /************************************/ |
| /****** EXIT CRITICAL SECTION ******/ |
| /************************************/ |
| |
| { |
| void *pv_mutex_handle_frame_init; |
| |
| /* Create mutex for locking non-reentrant sections */ |
| pv_mutex_handle_frame_init = |
| ps_enc_ctxt->s_multi_thrd.apv_mutex_handle_me_end[i4_me_frm_id]; |
| /****** Unlock the critical section ******/ |
| if(NULL != pv_mutex_handle_frame_init) |
| { |
| result = osal_mutex_unlock(pv_mutex_handle_frame_init); |
| if(OSAL_SUCCESS != result) |
| return 0; |
| } |
| } |
| /* -------------------------------------------- */ |
| /* Encode Loop of entire frame */ |
| /* -------------------------------------------- */ |
| ASSERT(ps_enc_ctxt->s_multi_thrd.i4_num_enc_loop_frm_pllel <= MAX_NUM_ENC_LOOP_PARALLEL); |
| |
| if(1 == ps_enc_ctxt->s_multi_thrd.i4_num_enc_loop_frm_pllel) |
| { |
| pv_dep_mngr_prev_frame_done = ps_enc_ctxt->s_multi_thrd.apv_dep_mngr_prev_frame_done[0]; |
| } |
| else |
| { |
| pv_dep_mngr_prev_frame_done = |
| ps_enc_ctxt->s_multi_thrd.apv_dep_mngr_prev_frame_done[i4_enc_frm_id]; |
| } |
| /* Wait till the prev frame enc loop is completed*/ |
| { |
| ihevce_dmgr_chk_frm_frm_sync(pv_dep_mngr_prev_frame_done, ps_thrd_ctxt->i4_thrd_id); |
| } |
| |
| /************************************/ |
| /****** ENTER CRITICAL SECTION ******/ |
| /************************************/ |
| { |
| WORD32 result_frame_init; |
| void *pv_mutex_handle_frame_init; |
| |
| /* Create mutex for locking non-reentrant sections */ |
| pv_mutex_handle_frame_init = |
| ps_enc_ctxt->s_multi_thrd.apv_mutex_handle_frame_init[i4_enc_frm_id]; |
| |
| /****** Lock the critical section ******/ |
| if(NULL != pv_mutex_handle_frame_init) |
| { |
| result_frame_init = osal_mutex_lock(pv_mutex_handle_frame_init); |
| |
| if(OSAL_SUCCESS != result_frame_init) |
| return 0; |
| } |
| } |
| |
| { |
| ihevce_lap_enc_buf_t *ps_curr_inp = NULL; |
| pre_enc_me_ctxt_t *ps_curr_inp_from_me = NULL; |
| me_enc_rdopt_ctxt_t *ps_curr_inp_enc = NULL; |
| pre_enc_L0_ipe_encloop_ctxt_t *ps_curr_L0_IPE_inp_prms = NULL; |
| recon_pic_buf_t *(*aps_ref_list)[HEVCE_MAX_REF_PICS * 2]; |
| WORD32 ai4_cur_qp[IHEVCE_MAX_NUM_BITRATES] = { 0 }; |
| WORD32 i4_field_pic = ps_enc_ctxt->s_runtime_src_prms.i4_field_pic; |
| WORD32 first_field = 1; |
| WORD32 result_frame_init; |
| void *pv_mutex_handle_frame_init; |
| |
| /* Create mutex for locking non-reentrant sections */ |
| pv_mutex_handle_frame_init = |
| ps_enc_ctxt->s_multi_thrd.apv_mutex_handle_frame_init[i4_enc_frm_id]; |
| |
| //aquire and initialize -> output and recon buffers |
| if(ps_enc_ctxt->s_multi_thrd.enc_master_done_frame_init[i4_enc_frm_id] == 0) |
| { |
| WORD32 |
| i4_bitrate_ctr; //bit-rate instance counter (for loop variable) [0->reference bit-rate, 1,2->auxiliarty bit-rates] |
| /* ------- get the input prms buffer from me que ------------ */ |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] = |
| (me_enc_rdopt_ctxt_t *)ihevce_q_get_filled_buff( |
| ps_enc_ctxt, |
| IHEVCE_ME_ENC_RDOPT_Q, |
| &ps_enc_ctxt->s_multi_thrd.i4_enc_in_buf_id[i4_enc_frm_id], |
| BUFF_QUE_BLOCKING_MODE); |
| i4_enc_end_flag = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id]->i4_end_flag; |
| |
| ASSERT(ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] != NULL); |
| |
| if(ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] != NULL) |
| { |
| ps_curr_inp = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id]->ps_curr_inp; |
| ps_curr_inp_from_me = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->ps_curr_inp_from_me_prms; |
| ps_curr_inp_enc = ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id]; |
| ps_curr_L0_IPE_inp_prms = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->ps_curr_inp_from_l0_ipe_prms; |
| |
| for(i4_bitrate_ctr = 0; i4_bitrate_ctr < i4_num_bitrates; i4_bitrate_ctr++) |
| { |
| iv_enc_recon_data_buffs_t |
| *ps_recon_out[MAX_NUM_ENC_LOOP_PARALLEL][IHEVCE_MAX_NUM_BITRATES] = { |
| { NULL } |
| }; |
| frm_proc_ent_cod_ctxt_t *ps_curr_out[MAX_NUM_ENC_LOOP_PARALLEL] |
| [IHEVCE_MAX_NUM_BITRATES] = { { NULL } }; |
| |
| /* ------- get free output buffer from Frame buffer que ---------- */ |
| /* There is a separate queue for each bit-rate instnace. The output |
| buffer is acquired from the corresponding queue based on the |
| bitrate instnace */ |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr] = |
| (frm_proc_ent_cod_ctxt_t *)ihevce_q_get_free_buff( |
| (void *)ps_enc_ctxt, |
| IHEVCE_FRM_PRS_ENT_COD_Q + |
| i4_bitrate_ctr, /*decides the buffer queue */ |
| &ps_enc_ctxt->s_multi_thrd.out_buf_id[i4_enc_frm_id][i4_bitrate_ctr], |
| BUFF_QUE_BLOCKING_MODE); |
| ps_enc_ctxt->s_multi_thrd.is_out_buf_freed[i4_enc_frm_id][i4_bitrate_ctr] = |
| 0; |
| ps_enc_ctxt->s_multi_thrd |
| .ps_curr_out_enc_grp[i4_enc_frm_id][i4_bitrate_ctr] = |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]; |
| //ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_enc_order_num = ps_curr_inp->s_lap_out.i4_enc_order_num; |
| /*registered User Data Call*/ |
| if(ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_sei_payload_enable_flag) |
| { |
| ihevce_fill_sei_payload( |
| ps_enc_ctxt, |
| ps_curr_inp, |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]); |
| } |
| |
| /*derive end flag and input valid flag in output buffer */ |
| if(NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id]) |
| { |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_end_flag = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->i4_end_flag; |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_frm_proc_valid_flag = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->i4_frm_proc_valid_flag; |
| |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_out_flush_flag = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->ps_curr_inp->s_lap_out.i4_out_flush_flag; |
| } |
| |
| /*derive other parameters in output buffer */ |
| if(NULL != ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr] && |
| (NULL != ps_curr_inp_from_me) && |
| (1 == ps_curr_inp->s_input_buf.i4_inp_frm_data_valid_flag) && |
| (i4_enc_end_flag == 0)) |
| { |
| /* copy the time stamps from inp to entropy inp */ |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_inp_timestamp_low = |
| ps_curr_inp_from_me->i4_inp_timestamp_low; |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_inp_timestamp_high = |
| ps_curr_inp_from_me->i4_inp_timestamp_high; |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->pv_app_frm_ctxt = |
| ps_curr_inp_from_me->pv_app_frm_ctxt; |
| |
| /*copy slice header params from temp structure to output buffer */ |
| memcpy( |
| &ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->s_slice_hdr, |
| &ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->s_slice_hdr, |
| sizeof(slice_header_t)); |
| |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr] |
| ->s_slice_hdr.pu4_entry_point_offset = |
| &ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr] |
| ->ai4_entry_point_offset[0]; |
| |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_slice_nal_type = |
| ps_curr_inp_from_me->i4_slice_nal_type; |
| |
| /* populate sps, vps and pps pointers for the entropy input params */ |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->ps_pps = |
| &ps_enc_ctxt->as_pps[i4_bitrate_ctr]; |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->ps_sps = |
| &ps_enc_ctxt->as_sps[i4_bitrate_ctr]; |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->ps_vps = |
| &ps_enc_ctxt->as_vps[i4_bitrate_ctr]; |
| |
| /* SEI header will be populated in pre-enocde stage */ |
| memcpy( |
| &ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->s_sei, |
| &ps_curr_inp_from_me->s_sei, |
| sizeof(sei_params_t)); |
| |
| /*AUD and EOS presnt flags are populated*/ |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i1_aud_present_flag = |
| ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_aud_enable_flags; |
| |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i1_eos_present_flag = |
| ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_eos_enable_flags; |
| |
| /* Information required for SEI Picture timing info */ |
| { |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_display_num = |
| ps_curr_inp->s_lap_out.i4_display_num; |
| } |
| |
| /* The Qp populated in Pre enc stage needs to overwritten with Qp |
| queried from rate control*/ |
| ps_curr_out[i4_enc_frm_id][i4_bitrate_ctr] |
| ->s_slice_hdr.i1_slice_qp_delta = |
| (WORD8)ps_curr_inp_from_me->i4_curr_frm_qp - |
| ps_enc_ctxt->as_pps[i4_bitrate_ctr].i1_pic_init_qp; |
| } |
| |
| /* ------- get a filled descriptor from output Que ------------ */ |
| if(/*(1 == ps_curr_inp->s_input_buf.i4_inp_frm_data_valid_flag) &&*/ |
| (ps_enc_ctxt->ps_stat_prms->i4_save_recon != 0)) |
| { |
| /*swaping of buf_id for 0th and reference bitrate location, as encoder |
| assumes always 0th loc for reference bitrate and app must receive in |
| the configured order*/ |
| WORD32 i4_recon_buf_id = i4_bitrate_ctr; |
| if(i4_bitrate_ctr == 0) |
| { |
| i4_recon_buf_id = ps_enc_ctxt->i4_ref_mbr_id; |
| } |
| else if(i4_bitrate_ctr == ps_enc_ctxt->i4_ref_mbr_id) |
| { |
| i4_recon_buf_id = 0; |
| } |
| |
| /* ------- get free Recon buffer from Frame buffer que ---------- */ |
| /* There is a separate queue for each bit-rate instnace. The recon |
| buffer is acquired from the corresponding queue based on the |
| bitrate instnace */ |
| ps_enc_ctxt->s_multi_thrd.ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr] = |
| (iv_enc_recon_data_buffs_t *)ihevce_q_get_filled_buff( |
| (void *)ps_enc_ctxt, |
| IHEVCE_RECON_DATA_Q + |
| i4_recon_buf_id, /*decides the buffer queue */ |
| &ps_enc_ctxt->s_multi_thrd |
| .recon_buf_id[i4_enc_frm_id][i4_bitrate_ctr], |
| BUFF_QUE_BLOCKING_MODE); |
| |
| ps_enc_ctxt->s_multi_thrd |
| .is_recon_dumped[i4_enc_frm_id][i4_bitrate_ctr] = 0; |
| ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr] = |
| ps_enc_ctxt->s_multi_thrd |
| .ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr]; |
| |
| ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_end_flag = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->i4_end_flag; |
| } |
| |
| } //bitrate ctr |
| } |
| } |
| if(ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] != NULL) |
| { |
| ps_curr_inp = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id]->ps_curr_inp; |
| ps_curr_inp_from_me = ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->ps_curr_inp_from_me_prms; |
| ps_curr_inp_enc = ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id]; |
| ps_curr_L0_IPE_inp_prms = |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->ps_curr_inp_from_l0_ipe_prms; |
| } |
| if((NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id]) && |
| ((1 == ps_curr_inp_enc->i4_frm_proc_valid_flag) && |
| (ps_enc_ctxt->s_multi_thrd.enc_master_done_frame_init[i4_enc_frm_id] == 0))) |
| { |
| for(i = 0; i < i4_num_bitrates; i++) |
| { |
| aps_ref_list = ps_curr_inp_enc->aps_ref_list[i]; |
| /* acquire mutex lock for rate control calls */ |
| osal_mutex_lock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| |
| /*utlize the satd data from pre enc stage to get more accurate estimate SAD for I pic*/ |
| if(ps_curr_inp->s_lap_out.i4_pic_type == IV_I_FRAME || |
| ps_curr_inp->s_lap_out.i4_pic_type == IV_IDR_FRAME) |
| { |
| ihevce_rc_update_cur_frm_intra_satd( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i], |
| ps_curr_inp_from_me->i8_frame_acc_satd_cost, |
| ps_enc_ctxt->i4_active_enc_frame_id); |
| } |
| |
| /*pels assuming satd/act is obtained for entire frame*/ |
| ps_curr_inp->s_rc_lap_out.i4_num_pels_in_frame_considered = |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_ht * |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_wd; |
| |
| /*Service pending request to change average bitrate if any*/ |
| { |
| LWORD64 i8_new_bitrate = |
| ihevce_rc_get_new_bitrate(ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0]); |
| LWORD64 i8_new_peak_bitrate = ihevce_rc_get_new_peak_bitrate( |
| ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0]); |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i8_buf_level_bitrate_change = -1; |
| if((i8_new_bitrate != -1) && |
| (i8_new_peak_bitrate != -1)) /*-1 indicates no pending request*/ |
| { |
| LWORD64 buffer_level = ihevce_rc_change_avg_bitrate( |
| ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0]); |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i8_buf_level_bitrate_change = buffer_level; |
| } |
| } |
| |
| if((1 == ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.i4_mres_single_out) && |
| (1 == ps_curr_inp->s_lap_out.i4_first_frm_new_res)) |
| { |
| /* Whenver change in resolution happens change the buffer level */ |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i8_buf_level_bitrate_change = 0; |
| } |
| #if 1 //KISH ELP |
| { |
| rc_bits_sad_t as_rc_frame_stat[IHEVCE_MAX_NUM_BITRATES]; |
| |
| if(ps_enc_ctxt->ai4_rc_query[i] == |
| ps_enc_ctxt->i4_max_fr_enc_loop_parallel_rc) //KISH |
| { |
| WORD32 out_buf_id[IHEVCE_MAX_NUM_BITRATES]; |
| WORD32 i4_pic_type; |
| WORD32 cur_qp[IHEVCE_MAX_NUM_BITRATES]; |
| ihevce_lap_output_params_t s_lap_out; |
| |
| rc_lap_out_params_t s_rc_lap_out; |
| WORD32 i4_suppress_bpic_update; |
| |
| ihevce_rc_store_retrive_update_info( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i], |
| &as_rc_frame_stat[i], |
| ps_enc_ctxt->i4_active_enc_frame_id, |
| i, |
| 2, |
| &out_buf_id[i], |
| &i4_pic_type, |
| &cur_qp[i], |
| (void *)&s_lap_out, |
| (void *)&s_rc_lap_out); |
| |
| i4_suppress_bpic_update = |
| (WORD32)(s_rc_lap_out.i4_rc_temporal_lyr_id > 1); |
| /*RC inter face update before update to happen only for ELP disabled */ |
| if(1 == ps_enc_ctxt->i4_max_fr_enc_loop_parallel_rc) |
| { |
| /* SGI & Enc Loop Parallelism related changes*/ |
| ihevce_rc_interface_update( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i], |
| (IV_PICTURE_CODING_TYPE_T)s_rc_lap_out.i4_rc_pic_type, |
| &s_rc_lap_out, |
| cur_qp[i], |
| i4_enc_frm_id_rc); |
| } |
| |
| ihevce_rc_update_pic_info( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i], |
| (as_rc_frame_stat[i].u4_total_texture_bits + |
| as_rc_frame_stat[i].u4_total_header_bits), //pass total bits |
| as_rc_frame_stat[i].u4_total_header_bits, |
| as_rc_frame_stat[i].u4_total_sad, |
| as_rc_frame_stat[i].u4_total_intra_sad, |
| (IV_PICTURE_CODING_TYPE_T)i4_pic_type, |
| cur_qp[i], |
| i4_suppress_bpic_update, |
| as_rc_frame_stat[i].i4_qp_normalized_8x8_cu_sum, |
| as_rc_frame_stat[i].i4_8x8_cu_sum, |
| as_rc_frame_stat[i].i8_sad_by_qscale, |
| &s_lap_out, |
| &s_rc_lap_out, |
| out_buf_id[i], |
| as_rc_frame_stat[i].u4_open_loop_intra_sad, |
| as_rc_frame_stat[i].i8_total_ssd_frame, |
| ps_enc_ctxt |
| ->i4_active_enc_frame_id); //ps_curr_out->i4_inp_timestamp_low) |
| |
| //DBG_PRINTF("\n Sad = %d \t total bits = %d ", s_rc_frame_stat.u4_total_sad, (s_rc_frame_stat.u4_total_texture_bits + s_rc_frame_stat.u4_total_header_bits)); |
| /*populate qp for pre enc*/ |
| |
| //g_count--; |
| ps_enc_ctxt->ai4_rc_query[i]--; |
| |
| if(i == (i4_num_bitrates - 1)) |
| { |
| ihevce_rc_cal_pre_enc_qp( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0]); |
| |
| ps_enc_ctxt->i4_active_enc_frame_id++; |
| ps_enc_ctxt->i4_active_enc_frame_id = |
| (ps_enc_ctxt->i4_active_enc_frame_id % |
| ps_enc_ctxt->i4_max_fr_enc_loop_parallel_rc); |
| } |
| } |
| } |
| #endif |
| if(ps_enc_ctxt->ai4_rc_query[i] < ps_enc_ctxt->i4_max_fr_enc_loop_parallel_rc) |
| { |
| /*HEVC_RC query rate control for qp*/ |
| ai4_cur_qp[i] = ihevce_rc_get_pic_quant( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i], |
| &ps_curr_inp->s_rc_lap_out, |
| ENC_GET_QP, |
| i4_enc_frm_id_rc, |
| 0, |
| &ps_curr_inp->s_lap_out.ai4_frame_bits_estimated[i]); |
| |
| ps_curr_inp->s_rc_lap_out.i4_orig_rc_qp = ai4_cur_qp[i]; |
| |
| ps_enc_ctxt->s_multi_thrd.i4_in_frame_rc_enabled = 0; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_sub_pic_level_rc = 0; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->ai4_frame_bits_estimated = |
| ps_curr_inp->s_lap_out.ai4_frame_bits_estimated[i]; |
| |
| { |
| ps_enc_ctxt->ai4_rc_query[i]++; |
| } |
| } |
| |
| /* SGI & Enc Loop Parallelism related changes*/ |
| ihevce_rc_interface_update( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i], |
| (IV_PICTURE_CODING_TYPE_T)ps_curr_inp->s_lap_out.i4_pic_type, |
| &ps_curr_inp->s_rc_lap_out, |
| ai4_cur_qp[i], |
| i4_enc_frm_id_rc); |
| |
| //DBG_PRINTF("HEVC_QP = %d MPEG2_QP = %d\n",cur_qp,gu1_HEVCToMpeg2Quant[cur_qp]);//i_model_print |
| |
| /* release mutex lock after rate control calls */ |
| osal_mutex_unlock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_slice_hdr.i1_slice_qp_delta = |
| (WORD8)ai4_cur_qp[i] - ps_enc_ctxt->as_pps[i].i1_pic_init_qp; |
| |
| ps_enc_ctxt->s_multi_thrd.cur_qp[i4_enc_frm_id][i] = ai4_cur_qp[i]; |
| |
| /* For interlace pictures, first_field depends on topfield_first and bottom field */ |
| if(i4_field_pic) |
| { |
| first_field = |
| (ps_curr_inp->s_input_buf.i4_topfield_first ^ |
| ps_curr_inp->s_input_buf.i4_bottom_field); |
| } |
| /* get frame level lambda params */ |
| ihevce_get_frame_lambda_prms( |
| ps_enc_ctxt, |
| ps_curr_inp_from_me, |
| ai4_cur_qp[i], |
| first_field, |
| ps_curr_inp->s_lap_out.i4_is_ref_pic, |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id, |
| ps_curr_inp->s_lap_out.f_i_pic_lamda_modifier, |
| i, |
| ENC_LOOP_LAMBDA_TYPE); |
| |
| #if ADAPT_COLOCATED_FROM_L0_FLAG |
| ps_enc_ctxt->s_multi_thrd.ps_frm_recon[i4_enc_frm_id][i]->i4_frame_qp = |
| ai4_cur_qp[i]; |
| #endif |
| } //bitrate counter ends |
| |
| /* Reset the Dependency Mngrs local to EncLoop., ie CU_TopRight and Dblk */ |
| ihevce_enc_loop_dep_mngr_frame_reset( |
| ps_enc_ctxt->s_module_ctxt.pv_enc_loop_ctxt, i4_enc_frm_id); |
| } |
| |
| { |
| /*Set the master done flag for frame init so that other |
| * threads can skip it |
| */ |
| ps_enc_ctxt->s_multi_thrd.enc_master_done_frame_init[i4_enc_frm_id] = 1; |
| } |
| |
| /************************************/ |
| /****** EXIT CRITICAL SECTION ******/ |
| /************************************/ |
| |
| /****** Unlock the critical section ******/ |
| if(NULL != pv_mutex_handle_frame_init) |
| { |
| result_frame_init = osal_mutex_unlock(pv_mutex_handle_frame_init); |
| if(OSAL_SUCCESS != result_frame_init) |
| return 0; |
| } |
| ps_enc_ctxt->s_multi_thrd.i4_encode = 1; |
| ps_enc_ctxt->s_multi_thrd.i4_num_re_enc = 0; |
| /************************************/ |
| /****** Do Enc loop process ******/ |
| /************************************/ |
| /* Each thread will run the enc-loop. |
| Each thread will initialize it's own enc_loop context and do the processing. |
| Each thread will run all the bit-rate instances one after another */ |
| if((i4_enc_end_flag == 0) && |
| (NULL != ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id]) && |
| (1 == ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->i4_frm_proc_valid_flag)) |
| { |
| while(1) |
| { |
| ctb_enc_loop_out_t *ps_ctb_enc_loop_frm[IHEVCE_MAX_NUM_BITRATES]; |
| cu_enc_loop_out_t *ps_cu_enc_loop_frm[IHEVCE_MAX_NUM_BITRATES]; |
| tu_enc_loop_out_t *ps_tu_frm[IHEVCE_MAX_NUM_BITRATES]; |
| pu_t *ps_pu_frm[IHEVCE_MAX_NUM_BITRATES]; |
| UWORD8 *pu1_frm_coeffs[IHEVCE_MAX_NUM_BITRATES]; |
| me_master_ctxt_t *ps_master_me_ctxt = |
| (me_master_ctxt_t *)ps_enc_ctxt->s_module_ctxt.pv_me_ctxt; |
| ihevce_enc_loop_master_ctxt_t *ps_master_ctxt = |
| (ihevce_enc_loop_master_ctxt_t *)ps_enc_ctxt->s_module_ctxt.pv_enc_loop_ctxt; |
| |
| for(i = 0; i < i4_num_bitrates; i++) |
| { |
| if(i4_thrd_id == 0) |
| { |
| PROFILE_START( |
| &ps_hle_ctxt->profile_enc[ps_enc_ctxt->i4_resolution_id][i]); |
| } |
| if(NULL != ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id]) |
| { |
| ps_ctb_enc_loop_frm[i] = |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->ps_frm_ctb_data; |
| ps_cu_enc_loop_frm[i] = |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->ps_frm_cu_data; |
| ps_tu_frm[i] = |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->ps_frm_tu_data; |
| ps_pu_frm[i] = |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->ps_frm_pu_data; |
| pu1_frm_coeffs[i] = (UWORD8 *)ps_enc_ctxt->s_multi_thrd |
| .ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->pv_coeff_data; |
| } |
| /*derive reference picture list based on ping or pong instnace */ |
| aps_ref_list = ps_curr_inp_enc->aps_ref_list[i]; |
| |
| /* Always consider chroma cost when computing cost for derived instance */ |
| ps_master_ctxt->aps_enc_loop_thrd_ctxt[i4_thrd_id]->i4_consider_chroma_cost = |
| 1; |
| |
| /************************* |
| * MULTI BITRATE CODE START |
| **************************/ |
| if(i4_num_bitrates > 1) |
| { |
| ihevce_mbr_quality_tool_set_configuration( |
| ps_master_ctxt->aps_enc_loop_thrd_ctxt[i4_thrd_id], |
| ps_enc_ctxt->ps_stat_prms); |
| } |
| /************************ |
| * MULTI BITRATE CODE END |
| *************************/ |
| /* picture level init of Encode loop module */ |
| ihevce_enc_loop_frame_init( |
| ps_enc_ctxt->s_module_ctxt.pv_enc_loop_ctxt, |
| ps_enc_ctxt->s_multi_thrd.cur_qp[i4_enc_frm_id][i], |
| aps_ref_list, |
| ps_enc_ctxt->s_multi_thrd.ps_frm_recon[i4_enc_frm_id][i], |
| &ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_slice_hdr, |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i]->ps_pps, |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i]->ps_sps, |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i]->ps_vps, |
| ps_curr_inp_enc->ps_curr_inp->s_lap_out.i1_weighted_pred_flag, |
| ps_curr_inp_enc->ps_curr_inp->s_lap_out.i1_weighted_bipred_flag, |
| ps_curr_inp_enc->ps_curr_inp->s_lap_out.i4_log2_luma_wght_denom, |
| ps_curr_inp_enc->ps_curr_inp->s_lap_out.i4_log2_chroma_wght_denom, |
| ps_curr_inp_enc->ps_curr_inp->s_lap_out.i4_poc, |
| ps_curr_inp_enc->ps_curr_inp->s_lap_out.i4_display_num, |
| ps_enc_ctxt, |
| ps_curr_inp_enc, |
| i, |
| i4_thrd_id, |
| i4_enc_frm_id, // update this to enc_loop_ctxt struct |
| i4_num_bitrates, |
| ps_curr_inp_enc->ps_curr_inp->s_lap_out.i4_quality_preset, |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->pv_dep_mngr_encloop_dep_me); |
| |
| ihevce_enc_loop_process( |
| ps_enc_ctxt->s_module_ctxt.pv_enc_loop_ctxt, |
| ps_curr_inp, |
| ps_curr_inp_from_me->ps_ctb_analyse, |
| ps_curr_L0_IPE_inp_prms->ps_ipe_analyse_ctb, |
| ps_enc_ctxt->s_multi_thrd.ps_frm_recon[i4_enc_frm_id][i], |
| ps_curr_inp_enc->ps_cur_ctb_cu_tree, |
| ps_ctb_enc_loop_frm[i], |
| ps_cu_enc_loop_frm[i], |
| ps_tu_frm[i], |
| ps_pu_frm[i], |
| pu1_frm_coeffs[i], |
| &ps_enc_ctxt->s_frm_ctb_prms, |
| &ps_curr_inp_from_me->as_lambda_prms[i], |
| &ps_enc_ctxt->s_multi_thrd, |
| i4_thrd_id, |
| i4_enc_frm_id, |
| ps_enc_ctxt->ps_stat_prms->s_pass_prms.i4_pass); |
| if(i4_thrd_id == 0) |
| { |
| PROFILE_STOP( |
| &ps_hle_ctxt->profile_enc[ps_enc_ctxt->i4_resolution_id][i], NULL); |
| } |
| } //loop over bitrate ends |
| { |
| break; |
| } |
| } /*end of while(ps_enc_ctxt->s_multi_thrd.ai4_encode[i4_enc_frm_id] == 1)*/ |
| } |
| |
| /************************************/ |
| /****** ENTER CRITICAL SECTION ******/ |
| /************************************/ |
| |
| /****** Lock the critical section ******/ |
| if(NULL != ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]) |
| { |
| result = osal_mutex_lock( |
| ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]); |
| |
| if(OSAL_SUCCESS != result) |
| return 0; |
| } |
| if(ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] != NULL) |
| { |
| /* Increment the counter to keep track of no of threads exiting the current mutex*/ |
| ps_enc_ctxt->s_multi_thrd.num_thrds_exited[i4_enc_frm_id]++; |
| |
| /* If the end frame is reached force the last slave to enter the next critical section*/ |
| if(i4_enc_end_flag == 1) |
| { |
| if(ps_enc_ctxt->s_multi_thrd.num_thrds_done == |
| ps_enc_ctxt->s_multi_thrd.i4_num_enc_proc_thrds - 1) |
| { |
| ps_enc_ctxt->s_multi_thrd.num_thrds_exited[i4_enc_frm_id] = |
| ps_enc_ctxt->s_multi_thrd.i4_num_enc_proc_thrds; |
| } |
| } |
| |
| { |
| /*Last slave thread comming out of enc loop will execute next critical section*/ |
| if(ps_enc_ctxt->s_multi_thrd.num_thrds_exited[i4_enc_frm_id] == |
| ps_enc_ctxt->s_multi_thrd.i4_num_enc_proc_thrds) |
| { |
| iv_enc_recon_data_buffs_t *ps_recon_out_temp = NULL; |
| recon_pic_buf_t *ps_frm_recon_temp = NULL; |
| ihevce_lap_enc_buf_t *ps_curr_inp; |
| rc_lap_out_params_t *ps_rc_lap_out_next_encode; |
| |
| WORD32 ai4_act_qp[IHEVCE_MAX_NUM_BITRATES]; |
| ps_enc_ctxt->s_multi_thrd.num_thrds_exited[i4_enc_frm_id] = 0; |
| |
| ps_curr_inp = ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->ps_curr_inp; |
| |
| for(i = 0; i < i4_num_bitrates; i++) |
| { |
| { |
| WORD32 j, i4_avg_QP; |
| ihevce_enc_loop_master_ctxt_t *ps_master_ctxt = |
| (ihevce_enc_loop_master_ctxt_t *) |
| ps_enc_ctxt->s_module_ctxt.pv_enc_loop_ctxt; |
| ihevce_enc_loop_ctxt_t *ps_ctxt, *ps_ctxt_temp; |
| ihevce_enc_loop_ctxt_t *ps_ctxt_last_thrd; |
| LWORD64 i8_total_cu_bits_into_qscale = 0, i8_total_cu_bits = 0; |
| UWORD32 total_frame_intra_sad = 0; |
| UWORD32 total_frame_inter_sad = 0; |
| UWORD32 total_frame_sad = 0; |
| |
| LWORD64 total_frame_intra_cost = 0; |
| LWORD64 total_frame_inter_cost = 0; |
| LWORD64 total_frame_cost = 0; |
| |
| ps_ctxt_last_thrd = |
| ps_master_ctxt->aps_enc_loop_thrd_ctxt[i4_thrd_id]; |
| if(ps_enc_ctxt->s_multi_thrd.i4_in_frame_rc_enabled) |
| { |
| WORD32 i4_total_ctb = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_horz * |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_vert; |
| |
| ai4_act_qp[i] = |
| ps_enc_ctxt->s_multi_thrd |
| .ai4_curr_qp_acc[ps_ctxt_last_thrd->i4_enc_frm_id][i] / |
| i4_total_ctb; |
| } |
| else |
| { |
| ai4_act_qp[i] = |
| ps_enc_ctxt->s_multi_thrd.cur_qp[i4_enc_frm_id][i]; |
| } |
| |
| ps_enc_ctxt->s_multi_thrd |
| .ai4_curr_qp_acc[ps_ctxt_last_thrd->i4_enc_frm_id][i] = 0; |
| |
| /*Reset all the values of sub pic rc to default after the frame is completed */ |
| { |
| ps_enc_ctxt->s_multi_thrd |
| .ai4_acc_ctb_ctr[ps_ctxt_last_thrd->i4_enc_frm_id][i] = 0; |
| ps_enc_ctxt->s_multi_thrd |
| .ai4_ctb_ctr[ps_ctxt_last_thrd->i4_enc_frm_id][i] = 0; |
| |
| ps_enc_ctxt->s_multi_thrd |
| .ai4_threshold_reached[ps_ctxt_last_thrd->i4_enc_frm_id][i] = |
| 0; |
| |
| ps_enc_ctxt->s_multi_thrd |
| .ai4_curr_qp_estimated[ps_ctxt_last_thrd->i4_enc_frm_id][i] = |
| (1 << QP_LEVEL_MOD_ACT_FACTOR); |
| |
| ps_enc_ctxt->s_multi_thrd |
| .af_acc_hdr_bits_scale_err[ps_ctxt_last_thrd->i4_enc_frm_id] |
| [i] = 0; |
| } |
| for(j = 0; j < ps_master_ctxt->i4_num_proc_thrds; j++) |
| { |
| /* ENC_LOOP state structure */ |
| ps_ctxt = ps_master_ctxt->aps_enc_loop_thrd_ctxt[j]; |
| |
| total_frame_intra_sad += |
| ps_ctxt |
| ->aaps_enc_loop_rc_params[ps_ctxt_last_thrd |
| ->i4_enc_frm_id][i] |
| ->u4_frame_intra_sad_acc; |
| total_frame_inter_sad += |
| ps_ctxt |
| ->aaps_enc_loop_rc_params[ps_ctxt_last_thrd |
| ->i4_enc_frm_id][i] |
| ->u4_frame_inter_sad_acc; |
| total_frame_sad += |
| ps_ctxt |
| ->aaps_enc_loop_rc_params[ps_ctxt_last_thrd |
| ->i4_enc_frm_id][i] |
| ->u4_frame_sad_acc; |
| |
| total_frame_intra_cost += |
| ps_ctxt |
| ->aaps_enc_loop_rc_params[ps_ctxt_last_thrd |
| ->i4_enc_frm_id][i] |
| ->i8_frame_intra_cost_acc; |
| total_frame_inter_cost += |
| ps_ctxt |
| ->aaps_enc_loop_rc_params[ps_ctxt_last_thrd |
| ->i4_enc_frm_id][i] |
| ->i8_frame_inter_cost_acc; |
| total_frame_cost += |
| ps_ctxt |
| ->aaps_enc_loop_rc_params[ps_ctxt_last_thrd |
| ->i4_enc_frm_id][i] |
| ->i8_frame_cost_acc; |
| /*Reset thrd id flag once the frame is completed */ |
| ps_enc_ctxt->s_multi_thrd |
| .ai4_thrd_id_valid_flag[ps_ctxt_last_thrd->i4_enc_frm_id][i] |
| [j] = -1; |
| } |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_pic_level_info.u4_frame_sad = total_frame_sad; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_pic_level_info.u4_frame_intra_sad = total_frame_intra_sad; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_pic_level_info.u4_frame_inter_sad = total_frame_inter_sad; |
| |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_pic_level_info.i8_frame_cost = total_frame_cost; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_pic_level_info.i8_frame_intra_cost = total_frame_intra_cost; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_pic_level_info.i8_frame_inter_cost = total_frame_inter_cost; |
| } |
| ps_enc_ctxt->s_multi_thrd.ai4_produce_outbuf[i4_enc_frm_id][i] = 1; |
| ps_recon_out_temp = |
| ps_enc_ctxt->s_multi_thrd.ps_recon_out[i4_enc_frm_id][i]; |
| ps_frm_recon_temp = |
| ps_enc_ctxt->s_multi_thrd.ps_frm_recon[i4_enc_frm_id][i]; |
| |
| /* end of frame processing only if current input is valid */ |
| if(1 == ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] |
| ->i4_frm_proc_valid_flag) |
| { |
| /* Calculate the SEI Hash if enabled */ |
| if(0 != |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_sei.i1_decoded_pic_hash_sei_flag) |
| { |
| void *pv_y_buf; |
| void *pv_u_buf; |
| |
| { |
| pv_y_buf = ps_frm_recon_temp->s_yuv_buf_desc.pv_y_buf; |
| pv_u_buf = ps_frm_recon_temp->s_yuv_buf_desc.pv_u_buf; |
| } |
| |
| ihevce_populate_hash_sei( |
| &ps_enc_ctxt->s_multi_thrd |
| .ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->s_sei, |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms |
| .i4_internal_bit_depth, |
| pv_y_buf, |
| ps_frm_recon_temp->s_yuv_buf_desc.i4_y_wd, |
| ps_frm_recon_temp->s_yuv_buf_desc.i4_y_ht, |
| ps_frm_recon_temp->s_yuv_buf_desc.i4_y_strd, |
| pv_u_buf, |
| ps_frm_recon_temp->s_yuv_buf_desc.i4_uv_wd, |
| ps_frm_recon_temp->s_yuv_buf_desc.i4_uv_ht, |
| ps_frm_recon_temp->s_yuv_buf_desc.i4_uv_strd, |
| 0, |
| 0); |
| } |
| /* Sending qp, poc and pic-type to entropy thread for printing on console */ |
| if(ps_enc_ctxt->ps_stat_prms->i4_log_dump_level != 0) |
| { |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_qp = |
| ps_enc_ctxt->s_multi_thrd.cur_qp[i4_enc_frm_id][i]; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_poc = ps_curr_inp->s_lap_out.i4_poc; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_pic_type = ps_curr_inp->s_lap_out.i4_pic_type; |
| } |
| |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_is_I_scenecut = |
| ((ps_curr_inp->s_lap_out.i4_scene_type == 1) && |
| (ps_curr_inp->s_lap_out.i4_pic_type == IV_IDR_FRAME || |
| ps_curr_inp->s_lap_out.i4_pic_type == IV_I_FRAME)); |
| |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_is_non_I_scenecut = |
| ((ps_curr_inp->s_lap_out.i4_scene_type == |
| SCENE_TYPE_SCENE_CUT) && |
| (ps_enc_ctxt->s_multi_thrd |
| .ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_is_I_scenecut == 0)); |
| |
| /*ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i]->i4_is_I_only_scd = ps_curr_inp->s_lap_out.i4_is_I_only_scd; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i]->i4_is_non_I_scd = ps_curr_inp->s_lap_out.i4_is_non_I_scd; |
| |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i]->i4_is_model_valid = ps_curr_inp->s_lap_out.i4_is_model_valid;*/ |
| |
| /* -------------------------------------------- */ |
| /* MSE Computation for PSNR */ |
| /* -------------------------------------------- */ |
| if(ps_enc_ctxt->ps_stat_prms->i4_log_dump_level != 0) |
| { |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_qp = |
| ps_enc_ctxt->s_multi_thrd.cur_qp[i4_enc_frm_id][i]; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_poc = ps_curr_inp->s_lap_out.i4_poc; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_pic_type = ps_curr_inp->s_lap_out.i4_pic_type; |
| } |
| |
| /* if non reference B picture */ |
| if(0 == ps_frm_recon_temp->i4_is_reference) |
| { |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] |
| ->i4_pic_type += 2; |
| } |
| |
| #define FORCE_EXT_REF_PIC 0 |
| |
| /* -------------------------------------------- */ |
| /* Dumping of recon to App Queue */ |
| /* -------------------------------------------- */ |
| if(1 == ps_enc_ctxt->ps_stat_prms->i4_save_recon) |
| { |
| { |
| WORD32 i, j; |
| UWORD8 *pu1_recon; |
| UWORD8 *pu1_chrm_buf_u; |
| UWORD8 *pu1_chrm_buf_v; |
| UWORD8 *pu1_curr_recon; |
| |
| pu1_recon = |
| (UWORD8 *)ps_frm_recon_temp->s_yuv_buf_desc.pv_y_buf; |
| |
| /** Copying Luma into recon buffer **/ |
| pu1_curr_recon = (UWORD8 *)ps_recon_out_temp->pv_y_buf; |
| |
| for(j = 0; j < ps_curr_inp->s_lap_out.s_input_buf.i4_y_ht; |
| j++) |
| { |
| memcpy( |
| pu1_curr_recon, |
| pu1_recon, |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_wd); |
| |
| pu1_recon += |
| ps_frm_recon_temp->s_yuv_buf_desc.i4_y_strd; |
| pu1_curr_recon += |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_wd; |
| } |
| |
| /* recon chroma is converted from Semiplanar to Planar for dumping */ |
| pu1_recon = |
| (UWORD8 *)ps_frm_recon_temp->s_yuv_buf_desc.pv_u_buf; |
| pu1_chrm_buf_u = (UWORD8 *)ps_recon_out_temp->pv_cb_buf; |
| pu1_chrm_buf_v = |
| pu1_chrm_buf_u + |
| ((ps_curr_inp->s_lap_out.s_input_buf.i4_uv_wd >> 1) * |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_ht); |
| |
| for(j = 0; j < ps_curr_inp->s_lap_out.s_input_buf.i4_uv_ht; |
| j++) |
| { |
| for(i = 0; |
| i<ps_curr_inp->s_lap_out.s_input_buf.i4_uv_wd>> 1; |
| i++) |
| { |
| *pu1_chrm_buf_u++ = *pu1_recon++; |
| *pu1_chrm_buf_v++ = *pu1_recon++; |
| } |
| |
| pu1_recon -= |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_wd; |
| pu1_recon += |
| ps_frm_recon_temp->s_yuv_buf_desc.i4_uv_strd; |
| } |
| |
| /* set the POC and number of bytes in Y & UV buf */ |
| ps_recon_out_temp->i4_poc = ps_frm_recon_temp->i4_poc; |
| ps_recon_out_temp->i4_y_pixels = |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_ht * |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_wd; |
| ps_recon_out_temp->i4_uv_pixels = |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_wd * |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_ht; |
| } |
| } |
| ps_frm_recon_temp->i4_non_ref_free_flag = 1; |
| /* -------------------------------------------- */ |
| /* End of picture updates */ |
| /* -------------------------------------------- */ |
| } |
| |
| /* After the MSE (or PSNR) computation is done we will update |
| these data in output buffer structure and then signal entropy |
| thread that the buffer is produced. */ |
| if(ps_enc_ctxt->s_multi_thrd.ai4_produce_outbuf[i4_enc_frm_id][i] == 1) |
| { |
| /* set the output buffer as produced */ |
| ihevce_q_set_buff_prod( |
| (void *)ps_enc_ctxt, |
| IHEVCE_FRM_PRS_ENT_COD_Q + i, |
| ps_enc_ctxt->s_multi_thrd.out_buf_id[i4_enc_frm_id][i]); |
| |
| ps_enc_ctxt->s_multi_thrd.is_out_buf_freed[i4_enc_frm_id][i] = 1; |
| ps_enc_ctxt->s_multi_thrd.ai4_produce_outbuf[i4_enc_frm_id][i] = 0; |
| } |
| |
| } //bit-rate counter ends |
| /* -------------------------------------------- */ |
| /* Frame level RC update */ |
| /* -------------------------------------------- */ |
| /* Query enc_loop to get the Parameters for Rate control */ |
| if(1 == ps_curr_inp->s_input_buf.i4_inp_frm_data_valid_flag) |
| { |
| frm_proc_ent_cod_ctxt_t *ps_curr_out = NULL; |
| /*HEVC_RC*/ |
| rc_bits_sad_t as_rc_frame_stat[IHEVCE_MAX_NUM_BITRATES]; |
| osal_mutex_lock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| |
| for(i = 0; i < i4_num_bitrates; i++) |
| { |
| /*each bit-rate RC params are collated by master thread */ |
| ihevce_enc_loop_get_frame_rc_prms( |
| ps_enc_ctxt->s_module_ctxt.pv_enc_loop_ctxt, |
| &as_rc_frame_stat[i], |
| i, |
| i4_enc_frm_id); |
| |
| /*update bits estimate on rd opt thread so that mismatch between rdopt and entropy can be taken care of*/ |
| ps_curr_out = |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i]; |
| |
| ps_rc_lap_out_next_encode = |
| (rc_lap_out_params_t *) |
| ps_curr_inp->s_rc_lap_out.ps_rc_lap_out_next_encode; |
| |
| ps_curr_out->i4_is_end_of_idr_gop = 0; |
| |
| if(NULL != ps_rc_lap_out_next_encode) |
| { |
| if(ps_rc_lap_out_next_encode->i4_rc_pic_type == IV_IDR_FRAME) |
| { |
| /*If the next pic is IDR, then signal end of gopf for current frame*/ |
| ps_curr_out->i4_is_end_of_idr_gop = 1; |
| } |
| } |
| else if(NULL == ps_rc_lap_out_next_encode) |
| { |
| /*If the lap out next is NULL, then end of sequence reached*/ |
| ps_curr_out->i4_is_end_of_idr_gop = 1; |
| } |
| |
| if(NULL == ps_curr_out) |
| { |
| DBG_PRINTF("error in getting curr out in encode loop\n"); |
| } |
| |
| //DBG_PRINTF("\nRDOPT head = %d RDOPT text = %d\n",s_rc_frame_stat.u4_total_header_bits,s_rc_frame_stat.u4_total_texture_bits); |
| /* acquire mutex lock for rate control calls */ |
| |
| /* Note : u4_total_intra_sad coming out of enc_loop */ |
| /* will not be accurate becos of intra gating */ |
| /* need to access the importance of this sad in RC */ |
| |
| //Store the rc update parameters for deterministic Enc loop parallelism |
| |
| { |
| ihevce_rc_store_retrive_update_info( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i], |
| &as_rc_frame_stat[i], |
| i4_enc_frm_id_rc, |
| i, |
| 1, |
| &ps_enc_ctxt->s_multi_thrd.out_buf_id[i4_enc_frm_id][i], |
| &ps_curr_inp->s_lap_out.i4_pic_type, |
| &ai4_act_qp[i], |
| (void *)&ps_curr_inp->s_lap_out, |
| (void *)&ps_curr_inp->s_rc_lap_out); // STORE |
| } |
| } |
| |
| /* release mutex lock after rate control calls */ |
| osal_mutex_unlock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| } |
| if((ps_enc_ctxt->ps_stat_prms->i4_save_recon != 0) /*&& |
| (1 == ps_curr_inp->s_input_buf.s_input_buf.i4_inp_frm_data_valid_flag)*/) |
| { |
| WORD32 i4_bitrate_ctr; |
| for(i4_bitrate_ctr = 0; i4_bitrate_ctr < i4_num_bitrates; |
| i4_bitrate_ctr++) |
| { |
| /*swaping of buf_id for 0th and reference bitrate location, as encoder |
| assumes always 0th loc for reference bitrate and app must receive in |
| the configured order*/ |
| WORD32 i4_recon_buf_id = i4_bitrate_ctr; |
| if(i4_bitrate_ctr == 0) |
| { |
| i4_recon_buf_id = ps_enc_ctxt->i4_ref_mbr_id; |
| } |
| else if(i4_bitrate_ctr == ps_enc_ctxt->i4_ref_mbr_id) |
| { |
| i4_recon_buf_id = 0; |
| } |
| |
| /* Call back to Apln. saying recon buffer is produced */ |
| ps_hle_ctxt->ihevce_output_recon_fill_done( |
| ps_hle_ctxt->pv_recon_cb_handle, |
| ps_enc_ctxt->s_multi_thrd |
| .ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr], |
| i4_recon_buf_id, /* br instance */ |
| i4_resolution_id /* res_intance */); |
| |
| /* --- release the current recon buffer ---- */ |
| ihevce_q_rel_buf( |
| (void *)ps_enc_ctxt, |
| (IHEVCE_RECON_DATA_Q + i4_recon_buf_id), |
| ps_enc_ctxt->s_multi_thrd |
| .recon_buf_id[i4_enc_frm_id][i4_bitrate_ctr]); |
| |
| ps_enc_ctxt->s_multi_thrd |
| .is_recon_dumped[i4_enc_frm_id][i4_bitrate_ctr] = 1; |
| } |
| } |
| |
| if(i4_enc_end_flag == 1) |
| { |
| if(ps_enc_ctxt->s_multi_thrd.is_in_buf_freed[i4_enc_frm_id] == 0) |
| { |
| /* release the pre_enc/enc queue buffer */ |
| ihevce_q_rel_buf( |
| (void *)ps_enc_ctxt, |
| IHEVCE_PRE_ENC_ME_Q, |
| ps_curr_inp_enc->curr_inp_from_me_buf_id); |
| |
| ps_enc_ctxt->s_multi_thrd.is_in_buf_freed[i4_enc_frm_id] = 1; |
| } |
| } |
| /* release encoder owned input buffer*/ |
| ihevce_q_rel_buf( |
| (void *)ps_enc_ctxt, |
| IHEVCE_INPUT_DATA_CTRL_Q, |
| ps_curr_inp_enc->curr_inp_buf_id); |
| /* release the pre_enc/enc queue buffer */ |
| ihevce_q_rel_buf( |
| ps_enc_ctxt, |
| IHEVCE_PRE_ENC_ME_Q, |
| ps_curr_inp_enc->curr_inp_from_me_buf_id); |
| |
| ps_enc_ctxt->s_multi_thrd.is_in_buf_freed[i4_enc_frm_id] = 1; |
| |
| /* release the pre_enc/enc queue buffer */ |
| ihevce_q_rel_buf( |
| ps_enc_ctxt, |
| IHEVCE_L0_IPE_ENC_Q, |
| ps_curr_inp_enc->curr_inp_from_l0_ipe_buf_id); |
| |
| ps_enc_ctxt->s_multi_thrd.is_L0_ipe_in_buf_freed[i4_enc_frm_id] = 1; |
| /* release the me/enc queue buffer */ |
| ihevce_q_rel_buf( |
| ps_enc_ctxt, |
| IHEVCE_ME_ENC_RDOPT_Q, |
| ps_enc_ctxt->s_multi_thrd.i4_enc_in_buf_id[i4_enc_frm_id]); |
| |
| /* reset the pointers to NULL */ |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] = NULL; |
| ps_enc_ctxt->s_multi_thrd.enc_master_done_frame_init[i4_enc_frm_id] = 0; |
| for(i = 0; i < i4_num_bitrates; i++) |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] = NULL; |
| |
| /* Set the prev_frame_done variable to 1 to indicate that |
| *prev frame is done */ |
| ihevce_dmgr_update_frm_frm_sync(pv_dep_mngr_prev_frame_done); |
| } |
| } |
| } |
| else |
| { |
| /* Increment the counter to keep track of no of threads exiting the current mutex*/ |
| ps_enc_ctxt->s_multi_thrd.num_thrds_exited[i4_enc_frm_id]++; |
| /*Last slave thread comming out of enc loop will execute next critical section*/ |
| if(ps_enc_ctxt->s_multi_thrd.num_thrds_exited[i4_enc_frm_id] == |
| ps_enc_ctxt->s_multi_thrd.i4_num_enc_proc_thrds) |
| { |
| ps_enc_ctxt->s_multi_thrd.num_thrds_exited[i4_enc_frm_id] = 0; |
| |
| /* reset the pointers to NULL */ |
| ps_enc_ctxt->s_multi_thrd.aps_cur_inp_enc_prms[i4_enc_frm_id] = NULL; |
| |
| ps_enc_ctxt->s_multi_thrd.enc_master_done_frame_init[i4_enc_frm_id] = 0; |
| |
| for(i = 0; i < i4_num_bitrates; i++) |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[i4_enc_frm_id][i] = NULL; |
| |
| /* Set the prev_frame_done variable to 1 to indicate that |
| *prev frame is done |
| */ |
| ihevce_dmgr_update_frm_frm_sync(pv_dep_mngr_prev_frame_done); |
| } |
| } |
| |
| /* Toggle the ping pong flag of the thread exiting curr frame*/ |
| /*ps_enc_ctxt->s_multi_thrd.ping_pong[ps_thrd_ctxt->i4_thrd_id] = |
| !ps_enc_ctxt->s_multi_thrd.ping_pong[ps_thrd_ctxt->i4_thrd_id];*/ |
| } |
| |
| /************************************/ |
| /****** EXIT CRITICAL SECTION ******/ |
| /************************************/ |
| /****** Unlock the critical section ******/ |
| if(NULL != ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]) |
| { |
| result = osal_mutex_unlock( |
| ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]); |
| if(OSAL_SUCCESS != result) |
| return 0; |
| } |
| |
| if((0 == i4_me_end_flag) && (0 == i4_enc_end_flag)) |
| { |
| i4_enc_frm_id++; |
| i4_enc_frm_id_rc++; |
| |
| if(i4_enc_frm_id == NUM_ME_ENC_BUFS) |
| { |
| i4_enc_frm_id = 0; |
| } |
| |
| if(i4_enc_frm_id_rc == ps_enc_ctxt->i4_max_fr_enc_loop_parallel_rc) |
| { |
| i4_enc_frm_id_rc = 0; |
| } |
| i4_me_frm_id++; |
| |
| if(i4_me_frm_id == NUM_ME_ENC_BUFS) |
| i4_me_frm_id = 0; |
| } |
| if(1 == ps_enc_ctxt->s_multi_thrd.i4_force_end_flag) |
| { |
| i4_me_end_flag = 1; |
| i4_enc_end_flag = 1; |
| } |
| } |
| |
| /****** Lock the critical section ******/ |
| |
| if(NULL != ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]) |
| { |
| WORD32 result; |
| |
| result = |
| osal_mutex_lock(ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]); |
| |
| if(OSAL_SUCCESS != result) |
| return 0; |
| } |
| |
| if(ps_enc_ctxt->s_multi_thrd.num_thrds_done == |
| (ps_enc_ctxt->s_multi_thrd.i4_num_enc_proc_thrds - 1)) |
| { |
| if(1 != ps_enc_ctxt->s_multi_thrd.i4_force_end_flag) |
| { |
| osal_mutex_lock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| for(i = 0; i < ps_enc_ctxt->i4_num_bitrates; i++) |
| { |
| ihevce_rc_close( |
| ps_enc_ctxt, |
| ps_enc_ctxt->i4_active_enc_frame_id, |
| 2, |
| MIN(ps_enc_ctxt->ai4_rc_query[i], ps_enc_ctxt->i4_max_fr_enc_loop_parallel_rc), |
| i); |
| } |
| osal_mutex_unlock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| } |
| } |
| |
| ps_enc_ctxt->s_multi_thrd.num_thrds_done++; |
| |
| /****** UnLock the critical section ******/ |
| if(NULL != ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]) |
| { |
| WORD32 result; |
| |
| result = |
| osal_mutex_unlock(ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]); |
| |
| if(OSAL_SUCCESS != result) |
| return 0; |
| } |
| |
| /****** Lock the critical section ******/ |
| if(NULL != ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]) |
| { |
| WORD32 result; |
| result = |
| osal_mutex_lock(ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]); |
| |
| if(OSAL_SUCCESS != result) |
| return 0; |
| } |
| if((ps_enc_ctxt->s_multi_thrd.num_thrds_done == |
| ps_enc_ctxt->s_multi_thrd.i4_num_enc_proc_thrds) && |
| (ps_enc_ctxt->s_multi_thrd.i4_force_end_flag)) |
| { |
| WORD32 num_bufs_preenc_me_que, num_bufs_L0_ipe_enc; |
| WORD32 buf_id_ctr, frm_id_ctr; |
| frm_proc_ent_cod_ctxt_t *ps_curr_out_enc_ent[IHEVCE_MAX_NUM_BITRATES]; |
| WORD32 out_buf_id_enc_ent[IHEVCE_MAX_NUM_BITRATES]; |
| |
| if(ps_enc_ctxt->s_multi_thrd.i4_num_enc_loop_frm_pllel > 1) |
| { |
| num_bufs_preenc_me_que = (MAX_L0_IPE_ENC_STAGGER - 1) + MIN_L1_L0_STAGGER_NON_SEQ + |
| NUM_BUFS_DECOMP_HME + |
| ps_enc_ctxt->ps_stat_prms->s_lap_prms.i4_rc_look_ahead_pics; |
| |
| num_bufs_L0_ipe_enc = MAX_L0_IPE_ENC_STAGGER; |
| } |
| else |
| { |
| num_bufs_preenc_me_que = (MIN_L0_IPE_ENC_STAGGER - 1) + MIN_L1_L0_STAGGER_NON_SEQ + |
| NUM_BUFS_DECOMP_HME + |
| ps_enc_ctxt->ps_stat_prms->s_lap_prms.i4_rc_look_ahead_pics; |
| |
| num_bufs_L0_ipe_enc = MIN_L0_IPE_ENC_STAGGER; |
| } |
| for(buf_id_ctr = 0; buf_id_ctr < num_bufs_preenc_me_que; buf_id_ctr++) |
| { |
| /* release encoder owned input buffer*/ |
| ihevce_q_rel_buf((void *)ps_enc_ctxt, IHEVCE_PRE_ENC_ME_Q, buf_id_ctr); |
| } |
| for(buf_id_ctr = 0; buf_id_ctr < num_bufs_L0_ipe_enc; buf_id_ctr++) |
| { |
| /* release encoder owned input buffer*/ |
| ihevce_q_rel_buf((void *)ps_enc_ctxt, IHEVCE_L0_IPE_ENC_Q, buf_id_ctr); |
| } |
| for(frm_id_ctr = 0; frm_id_ctr < NUM_ME_ENC_BUFS; frm_id_ctr++) |
| { |
| for(i = 0; i < ps_enc_ctxt->i4_num_bitrates; i++) |
| { |
| if(NULL != ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[frm_id_ctr][i]) |
| { |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[frm_id_ctr][i] |
| ->i4_frm_proc_valid_flag = 0; |
| ps_enc_ctxt->s_multi_thrd.ps_curr_out_enc_grp[frm_id_ctr][i]->i4_end_flag = 1; |
| /* set the output buffer as produced */ |
| ihevce_q_set_buff_prod( |
| (void *)ps_enc_ctxt, |
| IHEVCE_FRM_PRS_ENT_COD_Q + i, |
| ps_enc_ctxt->s_multi_thrd.out_buf_id[frm_id_ctr][i]); |
| } |
| } |
| } |
| for(buf_id_ctr = 0; buf_id_ctr < NUM_FRMPROC_ENTCOD_BUFS; |
| buf_id_ctr++) /*** Set buffer produced for NUM_FRMPROC_ENTCOD_BUFS buffers for entropy to exit ***/ |
| { |
| for(i = 0; i < ps_enc_ctxt->i4_num_bitrates; i++) |
| { |
| ps_curr_out_enc_ent[i] = (frm_proc_ent_cod_ctxt_t *)ihevce_q_get_free_buff( |
| (void *)ps_enc_ctxt, |
| IHEVCE_FRM_PRS_ENT_COD_Q + i, /*decides the buffer queue */ |
| &out_buf_id_enc_ent[i], |
| BUFF_QUE_NON_BLOCKING_MODE); |
| if(NULL != ps_curr_out_enc_ent[i]) |
| { |
| ps_curr_out_enc_ent[i]->i4_frm_proc_valid_flag = 0; |
| ps_curr_out_enc_ent[i]->i4_end_flag = 1; |
| /* set the output buffer as produced */ |
| ihevce_q_set_buff_prod( |
| (void *)ps_enc_ctxt, IHEVCE_FRM_PRS_ENT_COD_Q + i, out_buf_id_enc_ent[i]); |
| } |
| } |
| } |
| } |
| |
| /* The last thread coming out of Enc. Proc. */ |
| /* Release all the Recon buffers the application might have queued in */ |
| if((ps_enc_ctxt->s_multi_thrd.num_thrds_done == |
| ps_enc_ctxt->s_multi_thrd.i4_num_enc_proc_thrds) && |
| (ps_enc_ctxt->ps_stat_prms->i4_save_recon != 0) && |
| (ps_enc_ctxt->s_multi_thrd.i4_is_recon_free_done == 0)) |
| { |
| WORD32 i4_bitrate_ctr; |
| |
| for(i4_bitrate_ctr = 0; i4_bitrate_ctr < i4_num_bitrates; i4_bitrate_ctr++) |
| { |
| WORD32 end_flag = 0; |
| while(0 == end_flag) |
| { |
| /*swaping of buf_id for 0th and reference bitrate location, as encoder |
| assumes always 0th loc for reference bitrate and app must receive in |
| the configured order*/ |
| WORD32 i4_recon_buf_id = i4_bitrate_ctr; |
| if(i4_bitrate_ctr == 0) |
| { |
| i4_recon_buf_id = ps_enc_ctxt->i4_ref_mbr_id; |
| } |
| else if(i4_bitrate_ctr == ps_enc_ctxt->i4_ref_mbr_id) |
| { |
| i4_recon_buf_id = 0; |
| } |
| |
| /* ------- get free Recon buffer from Frame buffer que ---------- */ |
| /* There is a separate queue for each bit-rate instnace. The recon |
| buffer is acquired from the corresponding queue based on the |
| bitrate instnace */ |
| ps_enc_ctxt->s_multi_thrd.ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr] = |
| (iv_enc_recon_data_buffs_t *)ihevce_q_get_filled_buff( |
| (void *)ps_enc_ctxt, |
| IHEVCE_RECON_DATA_Q + i4_recon_buf_id, /*decides the buffer queue */ |
| &ps_enc_ctxt->s_multi_thrd.recon_buf_id[i4_enc_frm_id][i4_bitrate_ctr], |
| BUFF_QUE_BLOCKING_MODE); |
| |
| /* Update the end_flag from application */ |
| end_flag = ps_enc_ctxt->s_multi_thrd.ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr] |
| ->i4_is_last_buf; |
| |
| ps_enc_ctxt->s_multi_thrd.ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_end_flag = |
| 1; |
| ps_enc_ctxt->s_multi_thrd.ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_y_pixels = |
| 0; |
| ps_enc_ctxt->s_multi_thrd.ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr]->i4_uv_pixels = |
| 0; |
| |
| /* Call back to Apln. saying recon buffer is produced */ |
| ps_hle_ctxt->ihevce_output_recon_fill_done( |
| ps_hle_ctxt->pv_recon_cb_handle, |
| ps_enc_ctxt->s_multi_thrd.ps_recon_out[i4_enc_frm_id][i4_bitrate_ctr], |
| i4_recon_buf_id, /* br instance */ |
| i4_resolution_id /* res_intance */); |
| |
| /* --- release the current recon buffer ---- */ |
| ihevce_q_rel_buf( |
| (void *)ps_enc_ctxt, |
| (IHEVCE_RECON_DATA_Q + i4_recon_buf_id), |
| ps_enc_ctxt->s_multi_thrd.recon_buf_id[i4_enc_frm_id][i4_bitrate_ctr]); |
| } |
| } |
| /* Set the recon free done flag */ |
| ps_enc_ctxt->s_multi_thrd.i4_is_recon_free_done = 1; |
| } |
| |
| /****** UnLock the critical section ******/ |
| if(NULL != ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]) |
| { |
| WORD32 result; |
| result = |
| osal_mutex_unlock(ps_enc_ctxt->s_multi_thrd.apv_post_enc_mutex_handle[i4_enc_frm_id]); |
| |
| if(OSAL_SUCCESS != result) |
| return 0; |
| } |
| |
| return (0); |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_set_pre_enc_prms \endif |
| * |
| * \brief |
| * Set CTB parameters |
| * Set ME params |
| * Set pps, sps, vps, vui params |
| * Do RC init |
| * |
| * \param[in] Encoder context pointer |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_set_pre_enc_prms(enc_ctxt_t *ps_enc_ctxt) |
| { |
| WORD32 i; |
| WORD32 i4_num_instance, |
| i4_resolution_id = ps_enc_ctxt->i4_resolution_id; //number of bit-rate instances |
| |
| i4_num_instance = ps_enc_ctxt->i4_num_bitrates; |
| |
| #if PIC_ALIGN_CTB_SIZE |
| |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd = |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_width + |
| SET_CTB_ALIGN( |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_width, |
| ps_enc_ctxt->s_frm_ctb_prms.i4_ctb_size); |
| |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_horz = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd / ps_enc_ctxt->s_frm_ctb_prms.i4_ctb_size; |
| |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_ht = |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_height + |
| SET_CTB_ALIGN( |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_height, |
| ps_enc_ctxt->s_frm_ctb_prms.i4_ctb_size); |
| |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_vert = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_ht / ps_enc_ctxt->s_frm_ctb_prms.i4_ctb_size; |
| #else // PIC_ALIGN_CTB_SIZE |
| /* Allign the frame width to min CU size */ |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd = |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_width + |
| SET_CTB_ALIGN( |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_width, |
| ps_enc_ctxt->s_frm_ctb_prms.i4_min_cu_size); |
| |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_horz = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd / ps_enc_ctxt->s_frm_ctb_prms.i4_ctb_size; |
| |
| if((ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd % |
| ps_enc_ctxt->s_frm_ctb_prms.i4_ctb_size) != 0) |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_horz = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_horz + 1; |
| |
| /* Allign the frame hieght to min CU size */ |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_ht = |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_height + |
| SET_CTB_ALIGN( |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id].i4_height, |
| ps_enc_ctxt->s_frm_ctb_prms.i4_min_cu_size); |
| |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_vert = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_ht / ps_enc_ctxt->s_frm_ctb_prms.i4_ctb_size; |
| |
| if((ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_ht % |
| ps_enc_ctxt->s_frm_ctb_prms.i4_ctb_size) != 0) |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_vert = |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_vert + 1; |
| |
| #endif // PIC_ALIGN_CTB_SIZE |
| |
| ps_enc_ctxt->s_frm_ctb_prms.i4_max_cus_in_row = ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_horz * |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_cus_in_ctb; |
| |
| ps_enc_ctxt->s_frm_ctb_prms.i4_max_pus_in_row = ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_horz * |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_pus_in_ctb; |
| |
| ps_enc_ctxt->s_frm_ctb_prms.i4_max_tus_in_row = ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_horz * |
| ps_enc_ctxt->s_frm_ctb_prms.i4_num_tus_in_ctb; |
| ihevce_coarse_me_set_resolution( |
| ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt, |
| 1, |
| &ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd, |
| &ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_ht); |
| |
| /*if Resolution need to be changed dynamically then needs to go to encode group */ |
| ihevce_me_set_resolution( |
| ps_enc_ctxt->s_module_ctxt.pv_me_ctxt, |
| 1, |
| &ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_wd, |
| &ps_enc_ctxt->s_frm_ctb_prms.i4_cu_aligned_pic_ht); |
| i4_num_instance = ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id] |
| .i4_num_bitrate_instances; |
| for(i = 0; i < i4_num_instance; i++) |
| { |
| WORD32 i4_id; |
| /*swaping of buf_id for 0th and reference bitrate location, as encoder |
| assumes always 0th loc for reference bitrate and app must receive in |
| the configured order*/ |
| if(i == 0) |
| { |
| i4_id = ps_enc_ctxt->i4_ref_mbr_id; |
| } |
| else if(i == ps_enc_ctxt->i4_ref_mbr_id) |
| { |
| i4_id = 0; |
| } |
| else |
| { |
| i4_id = i; |
| } |
| /* populate vps based on encoder configuration and tools */ |
| ihevce_populate_vps( |
| ps_enc_ctxt, |
| &ps_enc_ctxt->as_vps[i], |
| &ps_enc_ctxt->s_runtime_src_prms, |
| &ps_enc_ctxt->ps_stat_prms->s_out_strm_prms, |
| &ps_enc_ctxt->s_runtime_coding_prms, |
| &ps_enc_ctxt->ps_stat_prms->s_config_prms, |
| ps_enc_ctxt->ps_stat_prms, |
| i4_resolution_id); |
| |
| /* populate sps based on encoder configuration and tools */ |
| ihevce_populate_sps( |
| ps_enc_ctxt, |
| &ps_enc_ctxt->as_sps[i], |
| &ps_enc_ctxt->as_vps[i], |
| &ps_enc_ctxt->s_runtime_src_prms, |
| &ps_enc_ctxt->ps_stat_prms->s_out_strm_prms, |
| &ps_enc_ctxt->s_runtime_coding_prms, |
| &ps_enc_ctxt->ps_stat_prms->s_config_prms, |
| &ps_enc_ctxt->s_frm_ctb_prms, |
| ps_enc_ctxt->ps_stat_prms, |
| i4_resolution_id); |
| |
| /* populate pps based on encoder configuration and tools */ |
| ihevce_populate_pps( |
| &ps_enc_ctxt->as_pps[i], |
| &ps_enc_ctxt->as_sps[i], |
| &ps_enc_ctxt->s_runtime_src_prms, |
| &ps_enc_ctxt->ps_stat_prms->s_out_strm_prms, |
| &ps_enc_ctxt->s_runtime_coding_prms, |
| &ps_enc_ctxt->ps_stat_prms->s_config_prms, |
| ps_enc_ctxt->ps_stat_prms, |
| i4_id, |
| i4_resolution_id, |
| ps_enc_ctxt->ps_tile_params_base, |
| &ps_enc_ctxt->ai4_column_width_array[0], |
| &ps_enc_ctxt->ai4_row_height_array[0]); |
| |
| // if(ps_enc_ctxt->as_sps[i].i1_vui_parameters_present_flag == 1) |
| { |
| ihevce_populate_vui( |
| &ps_enc_ctxt->as_sps[i].s_vui_parameters, |
| &ps_enc_ctxt->as_sps[i], |
| &ps_enc_ctxt->s_runtime_src_prms, |
| &ps_enc_ctxt->ps_stat_prms->s_vui_sei_prms, |
| i4_resolution_id, |
| &ps_enc_ctxt->s_runtime_tgt_params, |
| ps_enc_ctxt->ps_stat_prms, |
| i4_id); |
| } |
| } |
| |
| osal_mutex_lock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| /* run the loop over all bit-rate instnaces */ |
| for(i = 0; i < i4_num_instance; i++) |
| { |
| /*HEVC_RC Do one time initialization of rate control*/ |
| ihevce_rc_init( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i], |
| &ps_enc_ctxt->s_runtime_src_prms, |
| &ps_enc_ctxt->s_runtime_tgt_params, |
| &ps_enc_ctxt->s_rc_quant, |
| &ps_enc_ctxt->ps_stat_prms->s_sys_api, |
| &ps_enc_ctxt->ps_stat_prms->s_lap_prms, |
| ps_enc_ctxt->i4_max_fr_enc_loop_parallel_rc); |
| |
| ihevce_vbv_complaince_init_level( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[i], |
| &ps_enc_ctxt->as_sps[i].s_vui_parameters); |
| } |
| osal_mutex_unlock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_pre_enc_init \endif |
| * |
| * \brief |
| * set out_buf params |
| * Calculate end_flag if flushmode on |
| * Slice initialization |
| * Populate SIE params |
| * reference list creation |
| * |
| * \param[in] Encoder context pointer |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_pre_enc_init( |
| enc_ctxt_t *ps_enc_ctxt, |
| ihevce_lap_enc_buf_t *ps_curr_inp, |
| pre_enc_me_ctxt_t *ps_curr_out, |
| WORD32 *pi4_end_flag_ret, |
| WORD32 *pi4_cur_qp_ret, |
| WORD32 *pi4_decomp_lyr_idx, |
| WORD32 i4_ping_pong) |
| { |
| WORD32 end_flag = 0; |
| WORD32 cur_qp; |
| //recon_pic_buf_t *ps_frm_recon; |
| WORD32 first_field = 1; |
| WORD32 i4_field_pic = ps_enc_ctxt->s_runtime_src_prms.i4_field_pic; |
| WORD32 i4_decomp_lyrs_idx = 0; |
| WORD32 i4_resolution_id = ps_enc_ctxt->i4_resolution_id; |
| WORD32 slice_type = ISLICE; |
| WORD32 nal_type; |
| WORD32 min_cu_size; |
| |
| WORD32 stasino_enabled; |
| |
| /* copy the time stamps from inp to entropy inp */ |
| ps_curr_out->i4_inp_timestamp_low = ps_curr_inp->s_input_buf.i4_inp_timestamp_low; |
| ps_curr_out->i4_inp_timestamp_high = ps_curr_inp->s_input_buf.i4_inp_timestamp_high; |
| ps_curr_out->pv_app_frm_ctxt = ps_curr_inp->s_input_buf.pv_app_frm_ctxt; |
| |
| /* get the min cu size from config params */ |
| min_cu_size = ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_min_log2_cu_size; |
| |
| min_cu_size = 1 << min_cu_size; |
| |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_wd = |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_wd + |
| SET_CTB_ALIGN(ps_curr_inp->s_lap_out.s_input_buf.i4_y_wd, min_cu_size); |
| |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_ht = |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_ht + |
| SET_CTB_ALIGN(ps_curr_inp->s_lap_out.s_input_buf.i4_y_ht, min_cu_size); |
| |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_wd = |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_wd + |
| SET_CTB_ALIGN(ps_curr_inp->s_lap_out.s_input_buf.i4_uv_wd, min_cu_size); |
| |
| if(IV_YUV_420SP_UV == ps_enc_ctxt->ps_stat_prms->s_src_prms.i4_chr_format) |
| { |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_ht = |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_ht + |
| SET_CTB_ALIGN(ps_curr_inp->s_lap_out.s_input_buf.i4_uv_ht, (min_cu_size >> 1)); |
| } |
| else if(IV_YUV_422SP_UV == ps_enc_ctxt->ps_stat_prms->s_src_prms.i4_chr_format) |
| { |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_ht = |
| ps_curr_inp->s_lap_out.s_input_buf.i4_uv_ht + |
| SET_CTB_ALIGN(ps_curr_inp->s_lap_out.s_input_buf.i4_uv_ht, min_cu_size); |
| } |
| |
| /* update the END flag from LAP out */ |
| end_flag = ps_curr_inp->s_lap_out.i4_end_flag; |
| ps_curr_out->i4_end_flag = end_flag; |
| ps_enc_ctxt->s_multi_thrd.i4_last_pic_flag = end_flag; |
| |
| /* ----------------------------------------------------------------------*/ |
| /* Slice initialization for current frame; Required for entropy context */ |
| /* ----------------------------------------------------------------------*/ |
| { |
| WORD32 cur_poc = ps_curr_inp->s_lap_out.i4_poc; |
| |
| /* max merge candidates derived based on quality preset for now */ |
| WORD32 max_merge_candidates = 2; |
| |
| /* pocs less than random acess poc tagged for discard as they */ |
| /* could be refering to pics before the cra. */ |
| |
| /* CRA case: as the leading pictures can refer the picture precedes the associated |
| IRAP(CRA) in decoding order, hence make it Random access skipped leading pictures (RASL)*/ |
| |
| if((1 == ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.i4_enable_temporal_scalability) && |
| (ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_max_temporal_layers == |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id)) //TEMPORALA_SCALABILITY CHANGES |
| { |
| if(ps_curr_inp->s_lap_out.i4_assoc_IRAP_poc) |
| { |
| nal_type = (cur_poc < ps_curr_inp->s_lap_out.i4_assoc_IRAP_poc) |
| ? (ps_curr_inp->s_lap_out.i4_is_ref_pic ? NAL_RASL_R : NAL_RASL_N) |
| : (ps_curr_inp->s_lap_out.i4_is_ref_pic ? NAL_TSA_R : NAL_TSA_N); |
| } |
| /* IDR case: as the leading pictures can't refer the picture precedes the associated |
| IRAP(IDR) in decoding order, hence make it Random access decodable leading pictures (RADL)*/ |
| else |
| { |
| nal_type = (cur_poc < ps_curr_inp->s_lap_out.i4_assoc_IRAP_poc) |
| ? (ps_curr_inp->s_lap_out.i4_is_ref_pic ? NAL_RADL_R : NAL_RADL_N) |
| : (ps_curr_inp->s_lap_out.i4_is_ref_pic ? NAL_TSA_R : NAL_TSA_N); |
| } |
| } |
| else |
| { |
| if(ps_curr_inp->s_lap_out.i4_assoc_IRAP_poc) |
| { |
| nal_type = (cur_poc < ps_curr_inp->s_lap_out.i4_assoc_IRAP_poc) |
| ? (ps_curr_inp->s_lap_out.i4_is_ref_pic ? NAL_RASL_R : NAL_RASL_N) |
| : (ps_curr_inp->s_lap_out.i4_is_ref_pic ? NAL_TRAIL_R : NAL_TRAIL_N); |
| } |
| /* IDR case: as the leading pictures can't refer the picture precedes the associated |
| IRAP(IDR) in decoding order, hence make it Random access decodable leading pictures (RADL)*/ |
| else |
| { |
| nal_type = (cur_poc < ps_curr_inp->s_lap_out.i4_assoc_IRAP_poc) |
| ? (ps_curr_inp->s_lap_out.i4_is_ref_pic ? NAL_RADL_R : NAL_RADL_N) |
| : (ps_curr_inp->s_lap_out.i4_is_ref_pic ? NAL_TRAIL_R : NAL_TRAIL_N); |
| } |
| } |
| |
| switch(ps_curr_inp->s_lap_out.i4_pic_type) |
| { |
| case IV_IDR_FRAME: |
| /* IDR pic */ |
| slice_type = ISLICE; |
| nal_type = NAL_IDR_W_LP; |
| cur_poc = 0; |
| ps_enc_ctxt->i4_cra_poc = cur_poc; |
| break; |
| |
| case IV_I_FRAME: |
| slice_type = ISLICE; |
| |
| if(ps_curr_inp->s_lap_out.i4_is_cra_pic) |
| { |
| nal_type = NAL_CRA; |
| } |
| |
| ps_enc_ctxt->i4_cra_poc = cur_poc; |
| break; |
| |
| case IV_P_FRAME: |
| slice_type = PSLICE; |
| break; |
| |
| case IV_B_FRAME: |
| /* TODO : Mark the nal type as NAL_TRAIL_N for non ref pics */ |
| slice_type = BSLICE; |
| break; |
| |
| default: |
| /* This should never occur */ |
| ASSERT(0); |
| } |
| |
| /* number of merge candidates and error metric chosen based on quality preset */ |
| switch(ps_curr_inp->s_lap_out.i4_quality_preset) |
| { |
| case IHEVCE_QUALITY_P0: |
| max_merge_candidates = 5; |
| break; |
| |
| case IHEVCE_QUALITY_P2: |
| max_merge_candidates = 5; |
| break; |
| |
| case IHEVCE_QUALITY_P3: |
| max_merge_candidates = 3; |
| break; |
| |
| case IHEVCE_QUALITY_P4: |
| case IHEVCE_QUALITY_P5: |
| case IHEVCE_QUALITY_P6: |
| max_merge_candidates = 2; |
| break; |
| |
| default: |
| ASSERT(0); |
| } |
| |
| /* acquire mutex lock for rate control calls */ |
| osal_mutex_lock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| { |
| ps_curr_inp->s_rc_lap_out.i4_num_pels_in_frame_considered = |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_ht * |
| ps_curr_inp->s_lap_out.s_input_buf.i4_y_wd; |
| |
| /*initialize the frame info stat inside LAP out, Data inside this will be populated in ihevce_rc_get_bpp_based_frame_qp call*/ |
| ps_curr_inp->s_rc_lap_out.ps_frame_info = &ps_curr_inp->s_frame_info; |
| |
| ps_curr_inp->s_rc_lap_out.i4_is_bottom_field = ps_curr_inp->s_input_buf.i4_bottom_field; |
| if(ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_rate_control_mode == 3) |
| { |
| /*for constant qp use same qp*/ |
| /*HEVC_RC query rate control for qp*/ |
| cur_qp = ihevce_rc_pre_enc_qp_query( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], |
| &ps_curr_inp->s_rc_lap_out, |
| 0); |
| } |
| else |
| { |
| cur_qp = ihevce_rc_get_bpp_based_frame_qp( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], &ps_curr_inp->s_rc_lap_out); |
| } |
| } |
| /* release mutex lock after rate control calls */ |
| osal_mutex_unlock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| |
| /* store the QP in output prms */ |
| /* The same qp is also used in enc thread only for ME*/ |
| ps_curr_out->i4_curr_frm_qp = cur_qp; |
| |
| /* slice header entropy syn memory is not valid in pre encode stage */ |
| ps_curr_out->s_slice_hdr.pu4_entry_point_offset = NULL; |
| |
| /* derive the flag which indicates if stasino is enabled */ |
| stasino_enabled = (ps_enc_ctxt->s_runtime_coding_prms.i4_vqet & |
| (1 << BITPOS_IN_VQ_TOGGLE_FOR_ENABLING_NOISE_PRESERVATION)) && |
| (ps_enc_ctxt->s_runtime_coding_prms.i4_vqet & |
| (1 << BITPOS_IN_VQ_TOGGLE_FOR_CONTROL_TOGGLER)); |
| |
| /* initialize the slice header */ |
| ihevce_populate_slice_header( |
| &ps_curr_out->s_slice_hdr, |
| &ps_enc_ctxt->as_pps[0], |
| &ps_enc_ctxt->as_sps[0], |
| nal_type, |
| slice_type, |
| 0, |
| 0, |
| ps_curr_inp->s_lap_out.i4_poc, |
| cur_qp, |
| max_merge_candidates, |
| ps_enc_ctxt->ps_stat_prms->s_pass_prms.i4_pass, |
| ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.as_tgt_params[i4_resolution_id] |
| .i4_quality_preset, |
| stasino_enabled); |
| |
| ps_curr_out->i4_slice_nal_type = nal_type; |
| |
| ps_curr_out->s_slice_hdr.u4_nuh_temporal_id = 0; |
| |
| if(1 == ps_enc_ctxt->ps_stat_prms->s_tgt_lyr_prms.i4_enable_temporal_scalability) |
| { |
| ps_curr_out->s_slice_hdr.u4_nuh_temporal_id = |
| (ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_max_temporal_layers == |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id); //TEMPORALA_SCALABILITY CHANGES |
| } |
| |
| /* populate sps, vps and pps pointers for the entropy input params */ |
| ps_curr_out->ps_pps = &ps_enc_ctxt->as_pps[0]; |
| ps_curr_out->ps_sps = &ps_enc_ctxt->as_sps[0]; |
| ps_curr_out->ps_vps = &ps_enc_ctxt->as_vps[0]; |
| } |
| |
| /* By default, Sei messages are set to 0, to avoid unintialised memory access */ |
| memset(&ps_curr_out->s_sei, 0, sizeof(sei_params_t)); |
| |
| /* VUI, SEI flags reset */ |
| ps_curr_out->s_sei.i1_sei_parameters_present_flag = 0; |
| ps_curr_out->s_sei.i1_buf_period_params_present_flag = 0; |
| ps_curr_out->s_sei.i1_pic_timing_params_present_flag = 0; |
| ps_curr_out->s_sei.i1_recovery_point_params_present_flag = 0; |
| ps_curr_out->s_sei.i1_decoded_pic_hash_sei_flag = 0; |
| ps_curr_out->s_sei.i4_sei_mastering_disp_colour_vol_params_present_flags = 0; |
| |
| if(ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_sei_enable_flag == 1) |
| { |
| /* insert buffering period, display volume, recovery point only at irap points */ |
| WORD32 insert_per_irap = |
| ((slice_type == ISLICE) && |
| (((NAL_IDR_N_LP == nal_type) || (NAL_CRA == nal_type)) || (NAL_IDR_W_LP == nal_type))); |
| |
| ps_curr_out->s_sei.i1_sei_parameters_present_flag = 1; |
| |
| /* populate Sei buffering period based on encoder configuration and tools */ |
| if(ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_sei_buffer_period_flags == 1) |
| { |
| ihevce_populate_buffering_period_sei( |
| &ps_curr_out->s_sei, |
| &ps_enc_ctxt->as_sps[0].s_vui_parameters, |
| &ps_enc_ctxt->as_sps[0], |
| &ps_enc_ctxt->ps_stat_prms->s_vui_sei_prms); |
| |
| ps_curr_out->s_sei.i1_buf_period_params_present_flag = insert_per_irap; |
| |
| ihevce_populate_active_parameter_set_sei( |
| &ps_curr_out->s_sei, &ps_enc_ctxt->as_vps[0], &ps_enc_ctxt->as_sps[0]); |
| } |
| |
| /* populate Sei picture timing based on encoder configuration and tools */ |
| if(ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_sei_pic_timing_flags == 1) |
| { |
| ihevce_populate_picture_timing_sei( |
| &ps_curr_out->s_sei, |
| &ps_enc_ctxt->as_sps[0].s_vui_parameters, |
| &ps_enc_ctxt->s_runtime_src_prms, |
| ps_curr_inp->s_input_buf.i4_bottom_field); |
| ps_curr_out->s_sei.i1_pic_timing_params_present_flag = 1; |
| } |
| |
| /* populate Sei recovery point based on encoder configuration and tools */ |
| if(ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_sei_recovery_point_flags == 1) |
| { |
| ihevce_populate_recovery_point_sei( |
| &ps_curr_out->s_sei, &ps_enc_ctxt->ps_stat_prms->s_vui_sei_prms); |
| ps_curr_out->s_sei.i1_recovery_point_params_present_flag = insert_per_irap; |
| } |
| |
| /* populate mastering_display_colour_volume parameters */ |
| if(ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_sei_mastering_disp_colour_vol_flags == 1) |
| { |
| ihevce_populate_mastering_disp_col_vol_sei( |
| &ps_curr_out->s_sei, &ps_enc_ctxt->ps_stat_prms->s_out_strm_prms); |
| |
| ps_curr_out->s_sei.i4_sei_mastering_disp_colour_vol_params_present_flags = |
| insert_per_irap; |
| } |
| |
| /* populate SEI Hash Flag based on encoder configuration */ |
| if(0 != ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_decoded_pic_hash_sei_flag) |
| { |
| /* Sanity checks */ |
| ASSERT(0 != ps_enc_ctxt->as_sps[0].i1_chroma_format_idc); |
| |
| ASSERT( |
| (0 < ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_decoded_pic_hash_sei_flag) && |
| (4 > ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_decoded_pic_hash_sei_flag)); |
| |
| /* MD5 is not supported now! picture_md5[cIdx][i] pblm */ |
| ASSERT(1 != ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_decoded_pic_hash_sei_flag); |
| |
| ps_curr_out->s_sei.i1_decoded_pic_hash_sei_flag = |
| ps_enc_ctxt->ps_stat_prms->s_out_strm_prms.i4_decoded_pic_hash_sei_flag; |
| } |
| } |
| |
| /* For interlace pictures, first_field depends on topfield_first and bottom field */ |
| if(i4_field_pic) |
| { |
| first_field = |
| (ps_curr_inp->s_input_buf.i4_topfield_first ^ ps_curr_inp->s_input_buf.i4_bottom_field); |
| } |
| |
| /* get frame level lambda params */ |
| ihevce_get_frame_lambda_prms( |
| ps_enc_ctxt, |
| ps_curr_out, |
| cur_qp, |
| first_field, |
| ps_curr_inp->s_lap_out.i4_is_ref_pic, |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id, |
| lamda_modifier_for_I_pic[4] /*mean TRF*/, |
| 0, |
| PRE_ENC_LAMBDA_TYPE); |
| /* Coarse ME and Decomp buffers sharing */ |
| { |
| UWORD8 *apu1_lyr_bufs[MAX_NUM_HME_LAYERS]; |
| WORD32 ai4_lyr_buf_strd[MAX_NUM_HME_LAYERS]; |
| |
| /* get the Decomposition frame buffer from ME */ |
| i4_decomp_lyrs_idx = ihevce_coarse_me_get_lyr_buf_desc( |
| ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt, &apu1_lyr_bufs[0], &ai4_lyr_buf_strd[0]); |
| /* register the buffers with decomp module along with frame init */ |
| ihevce_decomp_pre_intra_frame_init( |
| ps_enc_ctxt->s_module_ctxt.pv_decomp_pre_intra_ctxt, |
| &apu1_lyr_bufs[0], |
| &ai4_lyr_buf_strd[0], |
| ps_curr_out->ps_layer1_buf, |
| ps_curr_out->ps_layer2_buf, |
| ps_curr_out->ps_ed_ctb_l1, |
| ps_curr_out->as_lambda_prms[0].i4_ol_sad_lambda_qf, |
| ps_curr_out->s_slice_hdr.i1_slice_type, |
| ps_curr_out->ps_ctb_analyse); |
| } |
| |
| /* -------------------------------------------------------- */ |
| /* Preparing Pre encode Passes Job Queue */ |
| /* -------------------------------------------------------- */ |
| ihevce_prepare_pre_enc_job_queue(ps_enc_ctxt, ps_curr_inp, i4_ping_pong); |
| |
| /*assign return variables */ |
| *pi4_end_flag_ret = end_flag; |
| *pi4_cur_qp_ret = cur_qp; |
| *pi4_decomp_lyr_idx = i4_decomp_lyrs_idx; |
| //*pps_frm_recon_ret = ps_frm_recon; |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_pre_enc_process_frame \endif |
| * |
| * \brief |
| * Frame processing main function |
| * |
| * \param[in] Encoder context pointer |
| * \param[in] Current input buffer params pointer |
| * \param[out] Current output buffer params pointer |
| * \param[in] Current frame QP |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_pre_enc_process_frame( |
| enc_ctxt_t *ps_enc_ctxt, |
| ihevce_lap_enc_buf_t *ps_curr_inp, |
| pre_enc_me_ctxt_t *ps_curr_out, |
| WORD32 i4_cur_frame_qp, |
| WORD32 i4_thrd_id, |
| WORD32 i4_ping_pong) |
| { |
| if(1 == ps_curr_out->i4_frm_proc_valid_flag) |
| { |
| /* ------------------------------------------------------------ */ |
| /* Layer Decomp and Intra 4x4 Analysis */ |
| /* ------------------------------------------------------------ */ |
| ihevce_decomp_pre_intra_process( |
| ps_enc_ctxt->s_module_ctxt.pv_decomp_pre_intra_ctxt, |
| &ps_curr_inp->s_lap_out, |
| &ps_enc_ctxt->s_frm_ctb_prms, |
| &ps_enc_ctxt->s_multi_thrd, |
| i4_thrd_id, |
| i4_ping_pong, |
| ps_curr_out->ps_layer0_cur_satd, |
| ps_curr_out->ps_layer0_cur_mean); |
| |
| /* ------------------------------------------------------------ */ |
| /* Coarse Motion estimation and early intra-inter decision */ |
| /* ------------------------------------------------------------ */ |
| ihevce_coarse_me_process( |
| ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt, |
| ps_curr_inp, |
| &ps_enc_ctxt->s_multi_thrd, |
| i4_thrd_id, |
| i4_ping_pong); |
| |
| /* ------------------------------------------------------------ */ |
| /* Update qp used in based in L1 satd/act in case of scene cut */ |
| /* ------------------------------------------------------------ */ |
| //ihevce_update_qp_L1_sad_based(ps_enc_ctxt,ps_curr_inp,ps_curr_out); |
| |
| /* Calculate the average activity values from the previous frame and |
| these would be used by the current frame*/ |
| /*ihevce_decomp_pre_intra_curr_frame_pre_intra_deinit( |
| ps_enc_ctxt->s_module_ctxt.pv_decomp_pre_intra_ctxt, |
| ps_enc_ctxt->s_module_ctxt.pv_ipe_ctxt, |
| i4_thrd_id);*/ |
| } |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_pre_enc_coarse_me_init \endif |
| * |
| * \brief |
| * set out_buf params |
| * Calculate end_flag if flushmode on |
| * Slice initialization |
| * Populate SIE params |
| * reference list creation |
| * |
| * \param[in] Encoder context pointer |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_pre_enc_coarse_me_init( |
| enc_ctxt_t *ps_enc_ctxt, |
| ihevce_lap_enc_buf_t *ps_curr_inp, |
| pre_enc_me_ctxt_t *ps_curr_out, |
| recon_pic_buf_t **pps_frm_recon_ret, |
| WORD32 i4_decomp_lyrs_idx, |
| WORD32 i4_cur_qp, |
| WORD32 i4_ping_pong) |
| |
| { |
| /* local variables */ |
| recon_pic_buf_t *ps_frm_recon; |
| coarse_me_master_ctxt_t *ps_ctxt = NULL; |
| ps_ctxt = (coarse_me_master_ctxt_t *)ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt; |
| /* Reference buffer management and reference list creation for pre enc group */ |
| ihevce_pre_enc_manage_ref_pics(ps_enc_ctxt, ps_curr_inp, ps_curr_out, i4_ping_pong); |
| |
| /* get a free recon buffer for current picture */ |
| { |
| WORD32 ctr; |
| |
| ps_frm_recon = NULL; |
| for(ctr = 0; ctr < ps_enc_ctxt->i4_pre_enc_num_buf_recon_q; ctr++) |
| { |
| if(1 == ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr]->i4_is_free) |
| { |
| ps_frm_recon = ps_enc_ctxt->pps_pre_enc_recon_buf_q[ctr]; |
| break; |
| } |
| } |
| } |
| /* should not be NULL */ |
| ASSERT(ps_frm_recon != NULL); |
| |
| /* populate reference /recon params based on LAP output */ |
| ps_frm_recon->i4_is_free = 0; |
| /* top first field is set to 1 by application */ |
| ps_frm_recon->i4_topfield_first = ps_curr_inp->s_input_buf.i4_topfield_first; |
| ps_frm_recon->i4_poc = ps_curr_inp->s_lap_out.i4_poc; |
| ps_frm_recon->i4_pic_type = ps_curr_inp->s_lap_out.i4_pic_type; |
| ps_frm_recon->i4_display_num = ps_curr_inp->s_lap_out.i4_display_num; |
| /* bottom field is toggled for every field by application */ |
| ps_frm_recon->i4_bottom_field = ps_curr_inp->s_input_buf.i4_bottom_field; |
| |
| /* Reference picture property is given by LAP */ |
| ps_frm_recon->i4_is_reference = ps_curr_inp->s_lap_out.i4_is_ref_pic; |
| |
| /* Deblock a picture for all reference frames unconditionally. */ |
| /* Deblock non ref if psnr compute or save recon is enabled */ |
| ps_frm_recon->i4_deblk_pad_hpel_cur_pic = ps_frm_recon->i4_is_reference || |
| (ps_enc_ctxt->ps_stat_prms->i4_save_recon); |
| |
| /* set the width, height and stride to defalut values */ |
| ps_frm_recon->s_yuv_buf_desc.i4_y_ht = 0; |
| ps_frm_recon->s_yuv_buf_desc.i4_uv_ht = 0; |
| ps_frm_recon->s_yuv_buf_desc.i4_y_wd = 0; |
| ps_frm_recon->s_yuv_buf_desc.i4_uv_wd = 0; |
| ps_frm_recon->s_yuv_buf_desc.i4_y_strd = 0; |
| ps_frm_recon->s_yuv_buf_desc.i4_uv_strd = 0; |
| |
| /* register the Layer1 MV bank pointer with ME module */ |
| ihevce_coarse_me_set_lyr1_mv_bank( |
| ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt, |
| ps_curr_inp, |
| ps_curr_out->pv_me_mv_bank, |
| ps_curr_out->pv_me_ref_idx, |
| i4_decomp_lyrs_idx); |
| |
| /* Coarse picture level init of ME */ |
| ihevce_coarse_me_frame_init( |
| ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt, |
| ps_enc_ctxt->ps_stat_prms, |
| &ps_enc_ctxt->s_frm_ctb_prms, |
| &ps_curr_out->as_lambda_prms[0], |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0, |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1, |
| ps_enc_ctxt->i4_pre_enc_num_ref_l0_active, |
| ps_enc_ctxt->i4_pre_enc_num_ref_l1_active, |
| &ps_enc_ctxt->aps_pre_enc_ref_lists[i4_ping_pong][LIST_0][0], |
| &ps_enc_ctxt->aps_pre_enc_ref_lists[i4_ping_pong][LIST_1][0], |
| ps_curr_inp, |
| i4_cur_qp, |
| ps_curr_out->ps_layer1_buf, |
| ps_curr_out->ps_ed_ctb_l1, |
| ps_curr_out->pu1_me_reverse_map_info, |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id); |
| |
| /*assign return variables */ |
| *pps_frm_recon_ret = ps_frm_recon; |
| } |
| |
| #define MAX_64BIT_VAL 0x7fffffffffffffff |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_variance_calc_acc_activity \endif |
| * |
| * \brief |
| * Function to calculate modulation based on spatial variance across lap period |
| * |
| * \param[in] pv_ctxt : pointer to IPE module |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| void ihevce_variance_calc_acc_activity(enc_ctxt_t *ps_enc_ctxt, WORD32 i4_cur_ipe_idx) |
| { |
| WORD32 j, i4_k; |
| WORD32 i = 0; |
| WORD32 is_i_frame = |
| ((ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_lap_out.i4_pic_type == |
| IV_I_FRAME) || |
| (ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_lap_out.i4_pic_type == |
| IV_IDR_FRAME)); |
| |
| WORD32 is_p_frame = |
| (ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_lap_out.i4_pic_type == |
| IV_P_FRAME); |
| |
| WORD32 i4_delay_loop = (ps_enc_ctxt->s_multi_thrd.i4_max_delay_pre_me_btw_l0_ipe + 1); |
| pre_enc_me_ctxt_t *ps_pre_enc_me_ctxt_t; |
| pre_enc_me_ctxt_t *ps_curr_out = ps_enc_ctxt->s_multi_thrd.aps_curr_out_pre_enc[i4_cur_ipe_idx]; |
| rc_lap_out_params_t *ps_temp_ipe_rc_lap_out; |
| UWORD8 is_no_scene_change = 1; |
| WORD32 loop_lap2, i4_pass_num; |
| UWORD32 u4_scene_num; |
| i4_pass_num = ps_enc_ctxt->ps_stat_prms->s_pass_prms.i4_pass; |
| ps_temp_ipe_rc_lap_out = |
| &ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_rc_lap_out; |
| ps_curr_out->i8_acc_frame_8x8_sum_act_sqr = 0; |
| ps_curr_out->i8_acc_frame_8x8_sum_act_for_strength = 0; |
| for(i4_k = 0; i4_k < 2; i4_k++) |
| { |
| ps_curr_out->i8_acc_frame_8x8_sum_act[i4_k] = 0; |
| ps_curr_out->i4_acc_frame_8x8_num_blks[i4_k] = 0; |
| |
| ps_curr_out->i8_acc_frame_16x16_sum_act[i4_k] = 0; |
| ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k] = 0; |
| |
| ps_curr_out->i8_acc_frame_32x32_sum_act[i4_k] = 0; |
| ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k] = 0; |
| } |
| ps_curr_out->i8_acc_frame_16x16_sum_act[i4_k] = 0; |
| ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k] = 0; |
| |
| ps_curr_out->i8_acc_frame_32x32_sum_act[i4_k] = 0; |
| ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k] = 0; |
| |
| u4_scene_num = |
| ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_lap_out.u4_scene_num; |
| |
| //ps_curr_out->i4_acc_frame_median_sum_act = 0; |
| |
| #if MODULATION_OVER_LAP |
| if(ps_enc_ctxt->s_multi_thrd.i4_delay_pre_me_btw_l0_ipe - 1 <= 0) |
| loop_lap2 = 1; |
| else |
| loop_lap2 = ps_enc_ctxt->s_multi_thrd.i4_delay_pre_me_btw_l0_ipe - 1; |
| #else |
| loop_lap2 = 1; |
| #endif |
| |
| if(ps_temp_ipe_rc_lap_out->ps_rc_lap_out_next_encode == NULL || |
| ps_temp_ipe_rc_lap_out->i4_is_non_I_scd) |
| { |
| is_no_scene_change = 0; |
| } |
| |
| /*Loop over complete lap2 struct ad make sure no scene change occurs in the lap2 frmaes */ |
| for(i = 1; i < loop_lap2; i++) |
| { |
| WORD32 i4_temp_ipe_idx = (i4_cur_ipe_idx + i) % i4_delay_loop; |
| if(0 == is_no_scene_change) |
| { |
| loop_lap2 = i; |
| break; |
| } |
| ps_temp_ipe_rc_lap_out = |
| &ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_temp_ipe_idx]->s_rc_lap_out; |
| |
| /*check if the current frame scene num is same as previous frame scene num */ |
| is_no_scene_change = (u4_scene_num == ps_temp_ipe_rc_lap_out->u4_rc_scene_num); |
| |
| if(ps_temp_ipe_rc_lap_out->ps_rc_lap_out_next_encode == NULL || |
| ps_temp_ipe_rc_lap_out->i4_is_non_I_scd) |
| { |
| is_no_scene_change = 0; |
| loop_lap2 = i; |
| break; |
| } |
| } |
| |
| /*Only if there is no scene change then process the lap2 for modulation index calcuation */ |
| if(((1 == is_i_frame) || (1 == is_p_frame)) && |
| (1 == is_no_scene_change || (ps_enc_ctxt->i4_active_scene_num != (WORD32)u4_scene_num))) |
| { |
| //do |
| ps_enc_ctxt->i4_active_scene_num = u4_scene_num; |
| for(i = 0; i < loop_lap2; i++) |
| { |
| WORD32 i4_temp_ipe_idx = (i4_cur_ipe_idx + i) % i4_delay_loop; |
| UWORD8 i_frame = |
| ((ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_temp_ipe_idx] |
| ->s_lap_out.i4_pic_type == IV_I_FRAME) || |
| (ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_temp_ipe_idx] |
| ->s_lap_out.i4_pic_type == IV_IDR_FRAME)); |
| UWORD8 p_frame = |
| (ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_temp_ipe_idx] |
| ->s_lap_out.i4_pic_type == IV_P_FRAME); |
| |
| ps_pre_enc_me_ctxt_t = ps_enc_ctxt->s_multi_thrd.aps_curr_out_pre_enc[i4_temp_ipe_idx]; |
| |
| if(1 == (p_frame || i_frame)) |
| { |
| ps_curr_out->i8_acc_frame_8x8_sum_act_sqr += |
| ps_pre_enc_me_ctxt_t->u8_curr_frame_8x8_sum_act_sqr; |
| ps_curr_out->i8_acc_frame_8x8_sum_act_for_strength += |
| ps_pre_enc_me_ctxt_t->i4_curr_frame_8x8_sum_act_for_strength[0]; |
| for(i4_k = 0; i4_k < 2; i4_k++) |
| { |
| ps_curr_out->i8_acc_frame_8x8_sum_act[i4_k] += |
| ps_pre_enc_me_ctxt_t->i8_curr_frame_8x8_sum_act[i4_k]; |
| ps_curr_out->i4_acc_frame_8x8_num_blks[i4_k] += |
| ps_pre_enc_me_ctxt_t->i4_curr_frame_8x8_num_blks[i4_k]; |
| |
| ps_curr_out->i8_acc_frame_16x16_sum_act[i4_k] += |
| ps_pre_enc_me_ctxt_t->i8_curr_frame_16x16_sum_act[i4_k]; |
| ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k] += |
| ps_pre_enc_me_ctxt_t->i4_curr_frame_16x16_num_blks[i4_k]; |
| |
| ps_curr_out->i8_acc_frame_32x32_sum_act[i4_k] += |
| ps_pre_enc_me_ctxt_t->i8_curr_frame_32x32_sum_act[i4_k]; |
| ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k] += |
| ps_pre_enc_me_ctxt_t->i4_curr_frame_32x32_num_blks[i4_k]; |
| } |
| |
| ps_curr_out->i8_acc_frame_16x16_sum_act[i4_k] += |
| ps_pre_enc_me_ctxt_t->i8_curr_frame_16x16_sum_act[i4_k]; |
| ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k] += |
| ps_pre_enc_me_ctxt_t->i4_curr_frame_16x16_num_blks[i4_k]; |
| |
| ps_curr_out->i8_acc_frame_32x32_sum_act[i4_k] += |
| ps_pre_enc_me_ctxt_t->i8_curr_frame_32x32_sum_act[i4_k]; |
| ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k] += |
| ps_pre_enc_me_ctxt_t->i4_curr_frame_32x32_num_blks[i4_k]; |
| |
| //ps_curr_out->i4_acc_frame_median_sum_act += ps_lap_out->i4_curr_frame_median_sum_act; |
| //ps_curr_out->i4_acc_frame_median_num_blks += ps_lap_out->i4_curr_frame_median_num_blks; |
| } |
| |
| //ps_is_next_frame_available = (ihevce_lap_output_params_t *)ps_is_next_frame_available->ps_lap_out_next_encode; |
| if(NULL == ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_temp_ipe_idx] |
| ->s_rc_lap_out.ps_rc_lap_out_next_encode) |
| break; |
| } //while(NULL != ps_is_next_frame_available); |
| |
| /*calculate corr. average, overwrite frame avg by acc. avergae*/ |
| { |
| for(i4_k = 0; i4_k < 2; i4_k++) |
| { |
| if(1 == is_i_frame) |
| { |
| ASSERT(0 != ps_curr_out->i4_acc_frame_8x8_num_blks[i4_k]); |
| ASSERT(0 != ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k]); |
| ASSERT(0 != ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k]); |
| } |
| |
| /*In P frame, if no occlusion is present, tehn accumalted avg can be 0*/ |
| /*In that case, modulation index is made 1*/ |
| if(0 == ps_curr_out->i4_acc_frame_8x8_num_blks[i4_k]) |
| { |
| ps_curr_out->i8_curr_frame_8x8_avg_act[i4_k] = 0; |
| } |
| else |
| { |
| ps_curr_out->i8_curr_frame_8x8_sum_act_for_strength = |
| (ps_curr_out->i8_acc_frame_8x8_sum_act_for_strength + |
| (ps_curr_out->i4_acc_frame_8x8_num_blks[i4_k] >> 1)) / |
| ps_curr_out->i4_acc_frame_8x8_num_blks[i4_k]; |
| ps_curr_out->i8_curr_frame_8x8_avg_act[i4_k] = |
| (ps_curr_out->i8_acc_frame_8x8_sum_act[i4_k] + |
| (ps_curr_out->i4_acc_frame_8x8_num_blks[i4_k] >> 1)) / |
| ps_curr_out->i4_acc_frame_8x8_num_blks[i4_k]; |
| ps_curr_out->ld_curr_frame_8x8_log_avg[i4_k] = |
| (log(1 + (long double)ps_curr_out->i8_curr_frame_8x8_avg_act[i4_k]) / |
| log(2.0)); |
| } |
| |
| if(0 == ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k]) |
| { |
| ps_curr_out->i8_curr_frame_16x16_avg_act[i4_k] = 0; |
| } |
| else |
| { |
| ps_curr_out->i8_curr_frame_16x16_avg_act[i4_k] = |
| (ps_curr_out->i8_acc_frame_16x16_sum_act[i4_k] + |
| (ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k] >> 1)) / |
| ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k]; |
| ps_curr_out->ld_curr_frame_16x16_log_avg[i4_k] = |
| (log(1 + (long double)ps_curr_out->i8_curr_frame_16x16_avg_act[i4_k]) / |
| log(2.0)); |
| } |
| |
| if(0 == ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k]) |
| { |
| ps_curr_out->i8_curr_frame_32x32_avg_act[i4_k] = 0; |
| } |
| else |
| { |
| ps_curr_out->i8_curr_frame_32x32_avg_act[i4_k] = |
| (ps_curr_out->i8_acc_frame_32x32_sum_act[i4_k] + |
| (ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k] >> 1)) / |
| ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k]; |
| ps_curr_out->ld_curr_frame_32x32_log_avg[i4_k] = |
| (log(1 + (long double)ps_curr_out->i8_curr_frame_32x32_avg_act[i4_k]) / |
| log(2.0)); |
| } |
| } |
| |
| if(1 == is_i_frame) |
| { |
| ASSERT(0 != ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k]); |
| ASSERT(0 != ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k]); |
| //ASSERT(0 != ps_curr_out->i4_acc_frame_median_num_blks); |
| } |
| if(0 == ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k]) |
| { |
| ps_curr_out->i8_curr_frame_16x16_avg_act[i4_k] = 0; |
| } |
| else |
| { |
| ps_curr_out->i8_curr_frame_16x16_avg_act[i4_k] = |
| (ps_curr_out->i8_acc_frame_16x16_sum_act[i4_k] + |
| (ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k] >> 1)) / |
| ps_curr_out->i4_acc_frame_16x16_num_blks[i4_k]; |
| ps_curr_out->ld_curr_frame_16x16_log_avg[i4_k] = |
| (log(1 + (long double)ps_curr_out->i8_curr_frame_16x16_avg_act[i4_k]) / |
| log(2.0)); |
| } |
| |
| if(0 == ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k]) |
| { |
| ps_curr_out->i8_curr_frame_32x32_avg_act[i4_k] = 0; |
| } |
| else |
| { |
| ps_curr_out->i8_curr_frame_32x32_avg_act[i4_k] = |
| (ps_curr_out->i8_acc_frame_32x32_sum_act[i4_k] + |
| (ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k] >> 1)) / |
| ps_curr_out->i4_acc_frame_32x32_num_blks[i4_k]; |
| ps_curr_out->ld_curr_frame_32x32_log_avg[i4_k] = |
| (log(1 + (long double)ps_curr_out->i8_curr_frame_32x32_avg_act[i4_k]) / |
| log(2.0)); |
| } |
| } |
| /*store the avg activity for B pictures*/ |
| { |
| #if POW_OPT |
| ps_enc_ctxt->ald_lap2_8x8_log_avg_act_from_T0[0] = |
| ps_curr_out->ld_curr_frame_8x8_log_avg[0]; |
| ps_enc_ctxt->ald_lap2_8x8_log_avg_act_from_T0[1] = |
| ps_curr_out->ld_curr_frame_8x8_log_avg[1]; |
| |
| ps_enc_ctxt->ald_lap2_16x16_log_avg_act_from_T0[0] = |
| ps_curr_out->ld_curr_frame_16x16_log_avg[0]; |
| ps_enc_ctxt->ald_lap2_16x16_log_avg_act_from_T0[1] = |
| ps_curr_out->ld_curr_frame_16x16_log_avg[1]; |
| ps_enc_ctxt->ald_lap2_16x16_log_avg_act_from_T0[2] = |
| ps_curr_out->ld_curr_frame_16x16_log_avg[2]; |
| |
| ps_enc_ctxt->ald_lap2_32x32_log_avg_act_from_T0[0] = |
| ps_curr_out->ld_curr_frame_32x32_log_avg[0]; |
| ps_enc_ctxt->ald_lap2_32x32_log_avg_act_from_T0[1] = |
| ps_curr_out->ld_curr_frame_32x32_log_avg[1]; |
| ps_enc_ctxt->ald_lap2_32x32_log_avg_act_from_T0[2] = |
| ps_curr_out->ld_curr_frame_32x32_log_avg[2]; |
| #else |
| ps_enc_ctxt->ai8_lap2_8x8_avg_act_from_T0[0] = |
| ps_curr_out->i8_curr_frame_8x8_avg_act[0]; |
| ps_enc_ctxt->ai8_lap2_8x8_avg_act_from_T0[1] = |
| ps_curr_out->i8_curr_frame_8x8_avg_act[1]; |
| |
| ps_enc_ctxt->ai8_lap2_16x16_avg_act_from_T0[0] = |
| ps_curr_out->i8_curr_frame_16x16_avg_act[0]; |
| ps_enc_ctxt->ai8_lap2_16x16_avg_act_from_T0[1] = |
| ps_curr_out->i8_curr_frame_16x16_avg_act[1]; |
| ps_enc_ctxt->ai8_lap2_16x16_avg_act_from_T0[2] = |
| ps_curr_out->i8_curr_frame_16x16_avg_act[2]; |
| |
| ps_enc_ctxt->ai8_lap2_32x32_avg_act_from_T0[0] = |
| ps_curr_out->i8_curr_frame_32x32_avg_act[0]; |
| ps_enc_ctxt->ai8_lap2_32x32_avg_act_from_T0[1] = |
| ps_curr_out->i8_curr_frame_32x32_avg_act[1]; |
| ps_enc_ctxt->ai8_lap2_32x32_avg_act_from_T0[2] = |
| ps_curr_out->i8_curr_frame_32x32_avg_act[2]; |
| #endif |
| } |
| /*Calculte modulation index */ |
| { |
| LWORD64 i8_mean, i8_mean_sqr, i8_variance; |
| LWORD64 i8_deviation; |
| WORD32 i4_mod_factor; |
| float f_strength; |
| |
| if(ps_curr_out->i4_acc_frame_8x8_num_blks[0] > 0) |
| { |
| #if STRENGTH_BASED_ON_CURR_FRM |
| i8_mean_sqr = |
| ((ps_curr_out->i8_curr_frame_8x8_sum_act_sqr + |
| (ps_curr_out->i4_curr_frame_8x8_num_blks[0] >> 1)) / |
| ps_curr_out->i4_curr_frame_8x8_num_blks[0]); |
| #else |
| i8_mean_sqr = |
| ((ps_curr_out->i8_acc_frame_8x8_sum_act_sqr + |
| (ps_curr_out->i4_acc_frame_8x8_num_blks[0] >> 1)) / |
| ps_curr_out->i4_acc_frame_8x8_num_blks[0]); |
| #endif |
| i8_mean = (ps_curr_out->i8_curr_frame_8x8_sum_act_for_strength); |
| |
| i8_variance = i8_mean_sqr - (i8_mean * i8_mean); |
| i8_deviation = (LWORD64)sqrt((long double)i8_variance); |
| #if STRENGTH_BASED_ON_DEVIATION |
| |
| if(((float)i8_deviation) <= (REF_MOD_DEVIATION)) |
| { |
| f_strength = |
| (float)((((float)i8_deviation - (BELOW_REF_DEVIATION)) * REF_MOD_STRENGTH) / ((REF_MOD_DEVIATION) - (BELOW_REF_DEVIATION))); |
| } |
| else |
| { |
| f_strength = |
| (float)((((float)i8_deviation - (ABOVE_REF_DEVIATION)) * REF_MOD_STRENGTH) / ((REF_MOD_DEVIATION) - (ABOVE_REF_DEVIATION))); |
| } |
| |
| #else |
| f_strength = (((float)((float)i8_mean_sqr / (float)(i8_mean * i8_mean)) - 1.0)) * |
| REF_MOD_STRENGTH / REF_MOD_VARIANCE; |
| #endif |
| i4_mod_factor = (WORD32)(i8_deviation / 60); |
| |
| f_strength = (float)CLIP3(f_strength, 0.0, REF_MAX_STRENGTH); |
| } |
| else |
| { |
| /*If not sufficient blocks are present, turn modulation index to 1 */ |
| i4_mod_factor = 1; |
| f_strength = 0; |
| } |
| ps_curr_out->ai4_mod_factor_derived_by_variance[0] = i4_mod_factor; |
| ps_curr_out->ai4_mod_factor_derived_by_variance[1] = i4_mod_factor; |
| ps_curr_out->f_strength = f_strength; |
| |
| if(1 == ps_enc_ctxt->s_runtime_src_prms.i4_field_pic) |
| { |
| /*For Interlace period, store mod factor and strenght if only first field*/ |
| if(1 == ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_lap_out.i4_first_field) |
| { |
| ps_enc_ctxt->ai4_mod_factor_derived_by_variance[0] = i4_mod_factor; |
| ps_enc_ctxt->ai4_mod_factor_derived_by_variance[1] = i4_mod_factor; |
| ps_enc_ctxt->f_strength = f_strength; |
| } |
| } |
| else |
| { |
| ps_enc_ctxt->ai4_mod_factor_derived_by_variance[0] = i4_mod_factor; |
| ps_enc_ctxt->ai4_mod_factor_derived_by_variance[1] = i4_mod_factor; |
| ps_enc_ctxt->f_strength = f_strength; |
| } |
| } |
| } |
| else |
| { |
| ps_curr_out->ai4_mod_factor_derived_by_variance[0] = |
| ps_enc_ctxt->ai4_mod_factor_derived_by_variance[0]; |
| ps_curr_out->ai4_mod_factor_derived_by_variance[1] = |
| ps_enc_ctxt->ai4_mod_factor_derived_by_variance[1]; |
| ps_curr_out->f_strength = ps_enc_ctxt->f_strength; |
| /*copy the prev avg activity from Tid 0 for B pictures*/ |
| { |
| #if POW_OPT |
| ps_curr_out->ld_curr_frame_8x8_log_avg[0] = |
| ps_enc_ctxt->ald_lap2_8x8_log_avg_act_from_T0[0]; |
| ps_curr_out->ld_curr_frame_8x8_log_avg[1] = |
| ps_enc_ctxt->ald_lap2_8x8_log_avg_act_from_T0[1]; |
| |
| ps_curr_out->ld_curr_frame_16x16_log_avg[0] = |
| ps_enc_ctxt->ald_lap2_16x16_log_avg_act_from_T0[0]; |
| ps_curr_out->ld_curr_frame_16x16_log_avg[1] = |
| ps_enc_ctxt->ald_lap2_16x16_log_avg_act_from_T0[1]; |
| ps_curr_out->ld_curr_frame_16x16_log_avg[2] = |
| ps_enc_ctxt->ald_lap2_16x16_log_avg_act_from_T0[2]; |
| |
| ps_curr_out->ld_curr_frame_32x32_log_avg[0] = |
| ps_enc_ctxt->ald_lap2_32x32_log_avg_act_from_T0[0]; |
| ps_curr_out->ld_curr_frame_32x32_log_avg[1] = |
| ps_enc_ctxt->ald_lap2_32x32_log_avg_act_from_T0[1]; |
| ps_curr_out->ld_curr_frame_32x32_log_avg[2] = |
| ps_enc_ctxt->ald_lap2_32x32_log_avg_act_from_T0[2]; |
| #else |
| ps_curr_out->i8_curr_frame_8x8_avg_act[0] = |
| ps_enc_ctxt->ai8_lap2_8x8_avg_act_from_T0[0]; |
| ps_curr_out->i8_curr_frame_8x8_avg_act[1] = |
| ps_enc_ctxt->ai8_lap2_8x8_avg_act_from_T0[1]; |
| |
| ps_curr_out->i8_curr_frame_16x16_avg_act[0] = |
| ps_enc_ctxt->ai8_lap2_16x16_avg_act_from_T0[0]; |
| ps_curr_out->i8_curr_frame_16x16_avg_act[1] = |
| ps_enc_ctxt->ai8_lap2_16x16_avg_act_from_T0[1]; |
| ps_curr_out->i8_curr_frame_16x16_avg_act[2] = |
| ps_enc_ctxt->ai8_lap2_16x16_avg_act_from_T0[2]; |
| |
| ps_curr_out->i8_curr_frame_32x32_avg_act[0] = |
| ps_enc_ctxt->ai8_lap2_32x32_avg_act_from_T0[0]; |
| ps_curr_out->i8_curr_frame_32x32_avg_act[1] = |
| ps_enc_ctxt->ai8_lap2_32x32_avg_act_from_T0[1]; |
| ps_curr_out->i8_curr_frame_32x32_avg_act[2] = |
| ps_enc_ctxt->ai8_lap2_32x32_avg_act_from_T0[2]; |
| #endif |
| } |
| } |
| |
| /*If Compenated block, then CLIP qp to max of frame qp and modulated qp*/ |
| { |
| WORD32 ctb_ctr, vert_ctr; |
| WORD32 ctb_ctr_blks = ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_horz; |
| WORD32 vert_ctr_blks = ps_enc_ctxt->s_frm_ctb_prms.i4_num_ctbs_vert; |
| ihevce_ed_ctb_l1_t *ps_ed_ctb_pic_l1 = |
| ps_enc_ctxt->s_multi_thrd.aps_curr_out_pre_enc[i4_cur_ipe_idx]->ps_ed_ctb_l1; |
| WORD32 i4_pic_type = |
| ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_lap_out.i4_pic_type; |
| for(vert_ctr = 0; vert_ctr < vert_ctr_blks; vert_ctr++) |
| { |
| ihevce_ed_ctb_l1_t *ps_ed_ctb_row_l1 = ps_ed_ctb_pic_l1 + vert_ctr * ctb_ctr_blks; |
| |
| for(ctb_ctr = 0; ctb_ctr < ctb_ctr_blks; ctb_ctr++) |
| { |
| ihevce_ed_ctb_l1_t *ps_ed_ctb_curr_l1 = ps_ed_ctb_row_l1 + ctb_ctr; |
| |
| WORD32 is_min_block_comensated_in_l32x32 = 0; |
| |
| /*Populate avg satd to calculate MI and activity factors*/ |
| for(i = 0; i < 4; i++) |
| { |
| WORD32 is_min_block_comensated_in_l116x16 = 0; |
| |
| for(j = 0; j < 4; j++) |
| { |
| /*Accumulate the sum of 8*8 activities in the current layer (16*16 CU in L0)*/ |
| if(ps_ed_ctb_curr_l1->i4_sum_4x4_satd[i * 4 + j] != -1) |
| { |
| WORD32 is_skipped = 0; |
| if((i4_pic_type != IV_I_FRAME) && (i4_pic_type != IV_IDR_FRAME) && |
| (1 == is_skipped)) |
| { |
| is_min_block_comensated_in_l116x16 += 1; |
| is_min_block_comensated_in_l32x32 += 1; |
| |
| if(ps_ed_ctb_curr_l1->i4_8x8_satd[i * 4 + j][0] < |
| ps_curr_out->i8_curr_frame_8x8_avg_act[0]) |
| ps_ed_ctb_curr_l1->i4_8x8_satd[i * 4 + j][0] = -1; |
| |
| if(ps_ed_ctb_curr_l1->i4_8x8_satd[i * 4 + j][1] < |
| ps_curr_out->i8_curr_frame_8x8_avg_act[1]) |
| ps_ed_ctb_curr_l1->i4_8x8_satd[i * 4 + j][1] = -1; |
| } |
| } |
| } |
| |
| if(4 == is_min_block_comensated_in_l116x16) |
| { |
| if(ps_ed_ctb_curr_l1->i4_16x16_satd[i][0] < |
| ps_curr_out->i8_curr_frame_16x16_avg_act[0]) |
| ps_ed_ctb_curr_l1->i4_16x16_satd[i][0] = -1; |
| |
| if(ps_ed_ctb_curr_l1->i4_16x16_satd[i][1] < |
| ps_curr_out->i8_curr_frame_16x16_avg_act[1]) |
| ps_ed_ctb_curr_l1->i4_16x16_satd[i][1] = -1; |
| |
| if(ps_ed_ctb_curr_l1->i4_16x16_satd[i][2] < |
| ps_curr_out->i8_curr_frame_16x16_avg_act[2]) |
| ps_ed_ctb_curr_l1->i4_16x16_satd[i][2] = -1; |
| } |
| } |
| |
| if((16 == is_min_block_comensated_in_l32x32)) |
| { |
| if(ps_ed_ctb_curr_l1->i4_32x32_satd[0][0] < |
| ps_curr_out->i8_curr_frame_32x32_avg_act[0]) |
| ps_ed_ctb_curr_l1->i4_32x32_satd[0][0] = -1; |
| |
| if(ps_ed_ctb_curr_l1->i4_32x32_satd[0][1] < |
| ps_curr_out->i8_curr_frame_32x32_avg_act[1]) |
| ps_ed_ctb_curr_l1->i4_32x32_satd[0][1] = -1; |
| |
| if(ps_ed_ctb_curr_l1->i4_32x32_satd[0][2] < |
| ps_curr_out->i8_curr_frame_32x32_avg_act[2]) |
| ps_ed_ctb_curr_l1->i4_32x32_satd[0][2] = -1; |
| } |
| } |
| } |
| } |
| |
| /**/ |
| return; |
| } |
| |
| /*! |
| ****************************************************************************** |
| * \if Function name : ihevce_pre_enc_process_frame_thrd \endif |
| * |
| * \brief |
| * Pre-Encode Frame processing thread interface function |
| * |
| * \param[in] High level encoder context pointer |
| * |
| * \return |
| * None |
| * |
| * \author |
| * Ittiam |
| * |
| ***************************************************************************** |
| */ |
| WORD32 ihevce_pre_enc_process_frame_thrd(void *pv_frm_proc_thrd_ctxt) |
| { |
| frm_proc_thrd_ctxt_t *ps_thrd_ctxt = (frm_proc_thrd_ctxt_t *)pv_frm_proc_thrd_ctxt; |
| ihevce_hle_ctxt_t *ps_hle_ctxt = ps_thrd_ctxt->ps_hle_ctxt; |
| enc_ctxt_t *ps_enc_ctxt = (enc_ctxt_t *)ps_thrd_ctxt->pv_enc_ctxt; |
| multi_thrd_ctxt_t *ps_multi_thrd = &ps_enc_ctxt->s_multi_thrd; |
| WORD32 i4_thrd_id = ps_thrd_ctxt->i4_thrd_id; |
| WORD32 i4_resolution_id = ps_enc_ctxt->i4_resolution_id; |
| WORD32 i4_end_flag = 0; |
| WORD32 i4_out_flush_flag = 0; |
| WORD32 i4_cur_decomp_idx = 0; |
| WORD32 i4_cur_coarse_me_idx = 0; |
| WORD32 i4_cur_ipe_idx = 0; |
| ihevce_lap_enc_buf_t *ps_lap_inp_buf = NULL; |
| void *pv_dep_mngr_prev_frame_pre_enc_l1 = ps_multi_thrd->pv_dep_mngr_prev_frame_pre_enc_l1; |
| void *pv_dep_mngr_prev_frame_pre_enc_l0 = ps_multi_thrd->pv_dep_mngr_prev_frame_pre_enc_l0; |
| void *pv_dep_mngr_prev_frame_pre_enc_coarse_me = |
| ps_multi_thrd->pv_dep_mngr_prev_frame_pre_enc_coarse_me; |
| WORD32 i4_num_buf_prod_for_l0_ipe = 0; |
| WORD32 i4_decomp_end_flag = 0; |
| |
| (void)ps_hle_ctxt; |
| (void)i4_resolution_id; |
| if(i4_thrd_id == 0) |
| { |
| PROFILE_START(&ps_hle_ctxt->profile_pre_enc[i4_resolution_id]); |
| } |
| |
| /* ---------- Processing Loop until Flush command is received --------- */ |
| while(0 == i4_end_flag) |
| { |
| /* Wait till previous frame(instance)'s decomp_intra is processed */ |
| { |
| ihevce_dmgr_chk_frm_frm_sync(pv_dep_mngr_prev_frame_pre_enc_l1, i4_thrd_id); |
| } |
| |
| /* ----------------------------------------------------------- */ |
| /* decomp pre_intra init */ |
| /* ----------------------------------------------------------- */ |
| |
| /****** Lock the critical section for decomp pre_intra init ******/ |
| { |
| WORD32 i4_status; |
| |
| i4_status = osal_mutex_lock(ps_multi_thrd->pv_mutex_hdl_pre_enc_init); |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| ps_multi_thrd->ai4_decomp_coarse_me_complete_flag[i4_cur_decomp_idx] = 0; |
| |
| /* init */ |
| if((ps_multi_thrd->ai4_pre_enc_init_done[i4_cur_decomp_idx] == 0) && |
| (0 == i4_decomp_end_flag)) |
| { |
| ihevce_lap_enc_buf_t *ps_curr_inp = NULL; |
| pre_enc_me_ctxt_t *ps_curr_out = NULL; |
| WORD32 in_buf_id; |
| WORD32 out_buf_id; |
| |
| do |
| { |
| ps_lap_inp_buf = NULL; |
| if(0 == ps_multi_thrd->i4_last_inp_buf) |
| { |
| /* ------- get input buffer input data que ---------- */ |
| ps_lap_inp_buf = (ihevce_lap_enc_buf_t *)ihevce_q_get_filled_buff( |
| (void *)ps_enc_ctxt, |
| IHEVCE_INPUT_DATA_CTRL_Q, |
| &in_buf_id, |
| BUFF_QUE_BLOCKING_MODE); |
| ps_multi_thrd->i4_last_inp_buf = ihevce_check_last_inp_buf( |
| (WORD32 *)ps_lap_inp_buf->s_input_buf.pv_synch_ctrl_bufs); |
| } |
| |
| ps_curr_inp = |
| ihevce_lap_process(ps_enc_ctxt->pv_lap_interface_ctxt, ps_lap_inp_buf); |
| |
| } while(NULL == ps_curr_inp); |
| |
| /* set the flag saying init is done so that other cores dont do it */ |
| ps_multi_thrd->ai4_pre_enc_init_done[i4_cur_decomp_idx] = 1; |
| |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_decomp_idx] = ps_curr_inp; |
| ps_multi_thrd->ai4_in_buf_id_pre_enc[i4_cur_decomp_idx] = |
| ps_curr_inp->s_input_buf.i4_buf_id; |
| |
| /* ------- get free output buffer from pre-enc/enc buffer que ---------- */ |
| ps_curr_out = (pre_enc_me_ctxt_t *)ihevce_q_get_free_buff( |
| (void *)ps_enc_ctxt, IHEVCE_PRE_ENC_ME_Q, &out_buf_id, BUFF_QUE_BLOCKING_MODE); |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_decomp_idx] = ps_curr_out; |
| ps_multi_thrd->ai4_out_buf_id_pre_enc[i4_cur_decomp_idx] = out_buf_id; |
| |
| if((NULL != ps_curr_inp) && (NULL != ps_curr_out)) |
| { |
| /* by default last picture to be encoded flag is set to 0 */ |
| /* this flag will be used by slave threads to exit at the end */ |
| ps_multi_thrd->i4_last_pic_flag = 0; |
| |
| /* store the buffer id */ |
| ps_curr_out->i4_buf_id = out_buf_id; |
| |
| ps_curr_out->i8_acc_num_blks_high_sad = 0; |
| ps_curr_out->i8_total_blks = 0; |
| ps_curr_out->i4_is_high_complex_region = -1; |
| |
| /* set the parameters for sync b/w pre-encode and encode threads */ |
| ps_curr_out->i4_end_flag = ps_curr_inp->s_lap_out.i4_end_flag; |
| ps_curr_out->i4_frm_proc_valid_flag = 1; |
| if(ps_curr_out->i4_end_flag) |
| { |
| ps_curr_out->i4_frm_proc_valid_flag = |
| ps_curr_inp->s_input_buf.i4_inp_frm_data_valid_flag; |
| ps_multi_thrd->i4_last_pic_flag = 1; |
| ps_multi_thrd->ai4_end_flag_pre_enc[i4_cur_decomp_idx] = 1; |
| } |
| if(ps_curr_inp->s_lap_out.i4_out_flush_flag) |
| { |
| ps_curr_out->i4_frm_proc_valid_flag = |
| ps_curr_inp->s_input_buf.i4_inp_frm_data_valid_flag; |
| } |
| |
| /* do the init processing if input frm data is valid */ |
| if(1 == ps_curr_inp->s_input_buf.i4_inp_frm_data_valid_flag) |
| { |
| WORD32 end_flag = ps_multi_thrd->ai4_end_flag_pre_enc[i4_cur_decomp_idx]; |
| WORD32 cur_qp = 0, count; |
| |
| ihevce_pre_enc_init( |
| ps_enc_ctxt, |
| ps_curr_inp, |
| ps_curr_out, |
| &end_flag, |
| &cur_qp, |
| &ps_multi_thrd->ai4_decomp_lyr_buf_idx[i4_cur_decomp_idx], |
| i4_cur_decomp_idx); |
| |
| ps_multi_thrd->ai4_end_flag_pre_enc[i4_cur_decomp_idx] = end_flag; |
| ps_multi_thrd->ai4_cur_frame_qp_pre_enc[i4_cur_decomp_idx] = cur_qp; |
| |
| for(count = 0; count < ((HEVCE_MAX_HEIGHT >> 1) / 8); count++) |
| { |
| ps_multi_thrd->aai4_l1_pre_intra_done[i4_cur_decomp_idx][count] = 0; |
| } |
| } |
| } |
| } |
| else if(1 == i4_decomp_end_flag) |
| { |
| /* Once end is reached all subsequent flags are set to 1 to indicate end */ |
| ps_multi_thrd->ai4_end_flag_pre_enc[i4_cur_decomp_idx] = 1; |
| } |
| |
| /****** UnLock the critical section after decomp pre_intra init ******/ |
| { |
| WORD32 i4_status; |
| i4_status = osal_mutex_unlock(ps_multi_thrd->pv_mutex_hdl_pre_enc_init); |
| |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /* Layer Decomp and Pre Intra Analysis */ |
| /* ------------------------------------------------------------ */ |
| if(0 == i4_decomp_end_flag) |
| { |
| pre_enc_me_ctxt_t *ps_curr_out = ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_decomp_idx]; |
| |
| if(1 == ps_curr_out->i4_frm_proc_valid_flag) |
| { |
| ihevce_decomp_pre_intra_process( |
| ps_enc_ctxt->s_module_ctxt.pv_decomp_pre_intra_ctxt, |
| &ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_decomp_idx]->s_lap_out, |
| &ps_enc_ctxt->s_frm_ctb_prms, |
| ps_multi_thrd, |
| i4_thrd_id, |
| i4_cur_decomp_idx, |
| ps_curr_out->ps_layer0_cur_satd, |
| ps_curr_out->ps_layer0_cur_mean); |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /* Layer Decomp and Pre Intra Deinit */ |
| /* ------------------------------------------------------------ */ |
| |
| /****** Lock the critical section for decomp deinit ******/ |
| { |
| WORD32 i4_status; |
| i4_status = osal_mutex_lock(ps_multi_thrd->pv_mutex_hdl_pre_enc_decomp_deinit); |
| |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| ps_multi_thrd->ai4_num_thrds_processed_decomp[i4_cur_decomp_idx]++; |
| i4_decomp_end_flag = ps_multi_thrd->ai4_end_flag_pre_enc[i4_cur_decomp_idx]; |
| |
| /* check for last thread condition */ |
| if(ps_multi_thrd->ai4_num_thrds_processed_decomp[i4_cur_decomp_idx] == |
| ps_multi_thrd->i4_num_pre_enc_proc_thrds) |
| { |
| ps_multi_thrd->ai4_num_thrds_processed_decomp[i4_cur_decomp_idx] = 0; |
| |
| /* reset the init flag so that init happens by the first thread for the next frame |
| of same ping_pong instance */ |
| ps_multi_thrd->ai4_pre_enc_init_done[i4_cur_decomp_idx] = 0; |
| |
| /* update the pre enc l1 done in dep manager */ |
| ihevce_dmgr_update_frm_frm_sync(pv_dep_mngr_prev_frame_pre_enc_l1); |
| } |
| |
| /* index increment */ |
| i4_cur_decomp_idx = i4_cur_decomp_idx + 1; |
| |
| /* wrap around case */ |
| if(i4_cur_decomp_idx == (MAX_PRE_ENC_STAGGER + NUM_BUFS_DECOMP_HME)) |
| { |
| i4_cur_decomp_idx = 0; |
| } |
| |
| /****** UnLock the critical section after decomp pre_intra deinit ******/ |
| { |
| WORD32 i4_status; |
| i4_status = osal_mutex_unlock(ps_multi_thrd->pv_mutex_hdl_pre_enc_decomp_deinit); |
| |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /* HME Init */ |
| /* ------------------------------------------------------------ */ |
| |
| /* Wait till previous frame(instance)'s coarse_me is processed */ |
| { |
| ihevce_dmgr_chk_frm_frm_sync(pv_dep_mngr_prev_frame_pre_enc_coarse_me, i4_thrd_id); |
| } |
| |
| /****** Lock the critical section for hme init ******/ |
| { |
| WORD32 i4_status; |
| |
| i4_status = osal_mutex_lock(ps_multi_thrd->pv_mutex_hdl_pre_enc_hme_init); |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| if(0 == ps_multi_thrd->ai4_pre_enc_hme_init_done[i4_cur_coarse_me_idx]) |
| { |
| /* do the init processing if input frm data is valid */ |
| if(1 == |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_coarse_me_idx]->i4_frm_proc_valid_flag) |
| { |
| recon_pic_buf_t *ps_frm_recon = NULL; |
| |
| /* DPB management for coarse me + HME init */ |
| ihevce_pre_enc_coarse_me_init( |
| ps_enc_ctxt, |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_coarse_me_idx], |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_coarse_me_idx], |
| &ps_frm_recon, |
| ps_multi_thrd->ai4_decomp_lyr_buf_idx[i4_cur_coarse_me_idx], |
| ps_multi_thrd->ai4_cur_frame_qp_pre_enc[i4_cur_coarse_me_idx], |
| i4_cur_coarse_me_idx); |
| |
| /* store the recon buffer pointer */ |
| ps_multi_thrd->aps_frm_recon_pre_enc[i4_cur_coarse_me_idx] = ps_frm_recon; |
| } |
| |
| ps_multi_thrd->ai4_pre_enc_hme_init_done[i4_cur_coarse_me_idx] = 1; |
| } |
| |
| /****** Unlock the critical section for hme init ******/ |
| { |
| WORD32 i4_status; |
| |
| i4_status = osal_mutex_unlock(ps_multi_thrd->pv_mutex_hdl_pre_enc_hme_init); |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /* Coarse Motion estimation and early intra-inter decision */ |
| /* ------------------------------------------------------------ */ |
| if(1 == ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_coarse_me_idx]->i4_frm_proc_valid_flag) |
| { |
| ihevce_coarse_me_process( |
| ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt, |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_coarse_me_idx], |
| &ps_enc_ctxt->s_multi_thrd, |
| i4_thrd_id, |
| i4_cur_coarse_me_idx); |
| } |
| |
| /* update the end flag */ |
| i4_end_flag = ps_multi_thrd->ai4_end_flag_pre_enc[i4_cur_coarse_me_idx]; |
| i4_out_flush_flag = |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_coarse_me_idx]->s_lap_out.i4_out_flush_flag; |
| |
| /****** Lock the critical section for hme deinit ******/ |
| { |
| WORD32 i4_status; |
| i4_status = osal_mutex_lock(ps_multi_thrd->pv_mutex_hdl_pre_enc_hme_deinit); |
| |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| /* last thread finishing pre_enc_process will update the flag indicating |
| decomp and coarse ME is done. So that the next frame (next ping_pong instance) |
| can start immediately after finishing current frame's IPE */ |
| if(1 == ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_coarse_me_idx]->i4_frm_proc_valid_flag) |
| { |
| ps_multi_thrd->ai4_num_thrds_processed_coarse_me[i4_cur_coarse_me_idx]++; |
| |
| /* ------------------------------------------------------------ */ |
| /* Update qp used in based in L1 satd/act in case of scene cut */ |
| /* ------------------------------------------------------------ */ |
| { |
| ihevce_lap_enc_buf_t *ps_curr_inp = |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_coarse_me_idx]; |
| |
| if(1 == ps_curr_inp->s_input_buf.i4_inp_frm_data_valid_flag) |
| { |
| WORD32 i4_prev_coarse_me_idx; |
| |
| /* wrap around case */ |
| if(i4_cur_coarse_me_idx == 0) |
| { |
| i4_prev_coarse_me_idx = MAX_PRE_ENC_STAGGER + NUM_BUFS_DECOMP_HME - 1; |
| } |
| else |
| { |
| i4_prev_coarse_me_idx = i4_cur_coarse_me_idx - 1; |
| } |
| |
| ihevce_update_qp_L1_sad_based( |
| ps_enc_ctxt, |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_coarse_me_idx], |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_prev_coarse_me_idx], |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_coarse_me_idx], |
| ((ps_multi_thrd->ai4_num_thrds_processed_coarse_me[i4_cur_coarse_me_idx] == |
| ps_multi_thrd->i4_num_pre_enc_proc_thrds))); |
| } |
| } |
| /* check for last thread condition */ |
| if(ps_multi_thrd->ai4_num_thrds_processed_coarse_me[i4_cur_coarse_me_idx] == |
| ps_multi_thrd->i4_num_pre_enc_proc_thrds) |
| { |
| ihevce_lap_enc_buf_t *ps_curr_inp = |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_coarse_me_idx]; |
| |
| /* Frame END processing */ |
| ihevce_coarse_me_frame_end(ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt); |
| |
| if(1 == ps_curr_inp->s_input_buf.i4_inp_frm_data_valid_flag) |
| { |
| WORD32 i4_enable_noise_detection = 0; |
| WORD32 i4_vqet = ps_enc_ctxt->ps_stat_prms->s_coding_tools_prms.i4_vqet; |
| |
| if(i4_vqet & (1 << BITPOS_IN_VQ_TOGGLE_FOR_CONTROL_TOGGLER)) |
| { |
| if(i4_vqet & (1 << BITPOS_IN_VQ_TOGGLE_FOR_ENABLING_NOISE_PRESERVATION)) |
| { |
| i4_enable_noise_detection = 1; |
| } |
| } |
| |
| if(1 != ((ps_curr_inp->s_lap_out.i4_pic_type == IV_B_FRAME) && |
| (ps_enc_ctxt->s_lap_stat_prms.ai4_quality_preset[i4_resolution_id] == |
| IHEVCE_QUALITY_P6))) |
| { |
| ihevce_decomp_pre_intra_curr_frame_pre_intra_deinit( |
| ps_enc_ctxt->s_module_ctxt.pv_decomp_pre_intra_ctxt, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_coarse_me_idx], |
| 1, |
| &ps_enc_ctxt->s_frm_ctb_prms, |
| ps_curr_inp->s_lap_out.i4_temporal_lyr_id, |
| i4_enable_noise_detection); |
| } |
| } |
| |
| ps_multi_thrd->ai4_decomp_coarse_me_complete_flag[i4_cur_coarse_me_idx] = 1; |
| |
| ps_multi_thrd->ai4_num_thrds_processed_coarse_me[i4_cur_coarse_me_idx] = 0; |
| |
| /* get the layer 1 ctxt to be passed on to encode group */ |
| ihevce_coarse_me_get_lyr1_ctxt( |
| ps_enc_ctxt->s_module_ctxt.pv_coarse_me_ctxt, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_coarse_me_idx]->pv_me_lyr_ctxt, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_coarse_me_idx]->pv_me_lyr_bnk_ctxt); |
| |
| /* reset the init flag so that init happens by the first thread for the next frame |
| of same ping_pong instance */ |
| ps_multi_thrd->ai4_pre_enc_hme_init_done[i4_cur_coarse_me_idx] = 0; |
| |
| /* update the pre enc l1 done in dep manager */ |
| ihevce_dmgr_update_frm_frm_sync(pv_dep_mngr_prev_frame_pre_enc_coarse_me); |
| } |
| |
| i4_num_buf_prod_for_l0_ipe++; |
| |
| /* index increment */ |
| i4_cur_coarse_me_idx = i4_cur_coarse_me_idx + 1; |
| |
| /* wrap around case */ |
| if(i4_cur_coarse_me_idx == (MAX_PRE_ENC_STAGGER + NUM_BUFS_DECOMP_HME)) |
| { |
| i4_cur_coarse_me_idx = 0; |
| } |
| } |
| else |
| { |
| /* for invalid frame set the processed flag to 1 for L0 IPE */ |
| ps_multi_thrd->ai4_decomp_coarse_me_complete_flag[i4_cur_coarse_me_idx] = 1; |
| |
| if(1 == i4_out_flush_flag) |
| { |
| /* update the num thrds who have finished pre-enc processing */ |
| ps_multi_thrd->ai4_num_thrds_processed_coarse_me[i4_cur_coarse_me_idx]++; |
| |
| if(ps_multi_thrd->ai4_num_thrds_processed_coarse_me[i4_cur_coarse_me_idx] == |
| ps_multi_thrd->i4_num_pre_enc_proc_thrds) |
| { |
| ps_multi_thrd->ai4_decomp_coarse_me_complete_flag[i4_cur_coarse_me_idx] = 1; |
| |
| /* reset num thread finished counter */ |
| ps_multi_thrd->ai4_num_thrds_processed_coarse_me[i4_cur_coarse_me_idx] = 0; |
| |
| ps_multi_thrd->ai4_pre_enc_hme_init_done[i4_cur_coarse_me_idx] = 0; |
| |
| /* update flag indicating coarse_me and decomp is done */ |
| ihevce_dmgr_update_frm_frm_sync(pv_dep_mngr_prev_frame_pre_enc_coarse_me); |
| } |
| } |
| |
| i4_num_buf_prod_for_l0_ipe++; |
| |
| /* index increment */ |
| i4_cur_coarse_me_idx = i4_cur_coarse_me_idx + 1; |
| |
| /* wrap around case */ |
| if(i4_cur_coarse_me_idx == (MAX_PRE_ENC_STAGGER + NUM_BUFS_DECOMP_HME)) |
| { |
| i4_cur_coarse_me_idx = 0; |
| } |
| } |
| |
| /****** UnLock the critical section after hme deinit ******/ |
| { |
| WORD32 i4_status; |
| i4_status = |
| osal_mutex_unlock(ps_enc_ctxt->s_multi_thrd.pv_mutex_hdl_pre_enc_hme_deinit); |
| |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| /* ----------------------------------------------------------- */ |
| /* IPE init and process */ |
| /* ----------------------------------------------------------- */ |
| |
| if(i4_num_buf_prod_for_l0_ipe >= ps_multi_thrd->i4_delay_pre_me_btw_l0_ipe || i4_end_flag || |
| i4_out_flush_flag) |
| { |
| do |
| { |
| /* Wait till previous frame(instance)'s IPE is processed */ |
| { |
| ihevce_dmgr_chk_frm_frm_sync(pv_dep_mngr_prev_frame_pre_enc_l0, i4_thrd_id); |
| } |
| |
| /* Wait till current frame(instance)'s L1 and below layers are processed */ |
| { |
| volatile WORD32 *pi4_cur_l1_complete = |
| &ps_multi_thrd->ai4_decomp_coarse_me_complete_flag[i4_cur_ipe_idx]; |
| |
| while(1) |
| { |
| if(*pi4_cur_l1_complete) |
| break; |
| } |
| } |
| |
| /* ----------------------------------------------------------- */ |
| /* L0 IPE qp init */ |
| /* ----------------------------------------------------------- */ |
| |
| /****** Lock the critical section for init ******/ |
| { |
| WORD32 i4_status; |
| i4_status = osal_mutex_lock(ps_multi_thrd->pv_mutex_hdl_l0_ipe_init); |
| |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| /* first thread that enters will calculate qp and write that to shared variable |
| that will be accessed by other threads */ |
| if(ps_multi_thrd->ai4_num_thrds_processed_L0_ipe_qp_init[i4_cur_ipe_idx] == 0) |
| { |
| volatile WORD32 i4_is_qp_valid = -1; |
| WORD32 i4_update_qp; |
| WORD32 i4_cur_q_scale; |
| |
| i4_cur_q_scale = |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx]->i4_curr_frm_qp; |
| i4_cur_q_scale = ps_enc_ctxt->s_rc_quant.pi4_qp_to_qscale[i4_cur_q_scale]; |
| i4_cur_q_scale = (i4_cur_q_scale + (1 << (QSCALE_Q_FAC_3 - 1))) >> |
| QSCALE_Q_FAC_3; |
| /* Get free buffer to store L0 IPE output to enc loop */ |
| ps_multi_thrd->ps_L0_IPE_curr_out_pre_enc = |
| (pre_enc_L0_ipe_encloop_ctxt_t *)ihevce_q_get_free_buff( |
| (void *)ps_enc_ctxt, |
| IHEVCE_L0_IPE_ENC_Q, |
| &ps_multi_thrd->i4_L0_IPE_out_buf_id, |
| BUFF_QUE_BLOCKING_MODE); |
| if(ps_enc_ctxt->ps_stat_prms->s_pass_prms.i4_pass != 2 && |
| ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_rate_control_mode != 3) |
| { |
| complexity_RC_reset_marking( |
| ps_enc_ctxt, i4_cur_ipe_idx, (i4_end_flag || i4_out_flush_flag)); |
| } |
| if(1 == ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_input_buf.i4_inp_frm_data_valid_flag) |
| { |
| 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 = ihevce_rc_check_is_pre_enc_qp_valid( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], |
| (volatile WORD32 *)&ps_enc_ctxt->s_multi_thrd.i4_force_end_flag); |
| if(1 == ps_enc_ctxt->s_multi_thrd.i4_force_end_flag) |
| { |
| /*** For force end condition break from this loop ***/ |
| i4_is_qp_valid = 1; |
| break; |
| } |
| } |
| |
| /*lock rate control context*/ |
| osal_mutex_lock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| |
| /* Qp query has to happen irrespective of using it or not since producer consumer logic will be disturbed */ |
| i4_update_qp = ihevce_rc_pre_enc_qp_query( |
| (void *)ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], |
| &ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_rc_lap_out, |
| 0); |
| |
| if(ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_rate_control_mode != 3) |
| { |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.i8_frm_satd_act_accum_L0_frm_L1 = |
| ihevce_get_L0_satd_based_on_L1( |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.i8_frame_satd_by_act_L1_accum, |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.i4_num_pels_in_frame_considered, |
| i4_cur_q_scale); |
| |
| if(ps_enc_ctxt->ps_stat_prms->s_pass_prms.i4_pass != 2) |
| { |
| if(ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.i4_rc_scene_type == |
| SCENE_TYPE_SCENE_CUT || |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.i4_is_I_only_scd || |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.i4_is_non_I_scd == 1) |
| { |
| float i_to_avg_rest_ratio; |
| WORD32 i4_count = 0; |
| |
| while(1) |
| { |
| i_to_avg_rest_ratio = ihevce_get_i_to_avg_ratio( |
| ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], |
| &ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out, |
| 1, |
| 0, |
| 0, |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.ai4_offsets, |
| 0); |
| /* HEVC_RC query rate control for qp */ |
| i4_update_qp = ihevce_get_L0_est_satd_based_scd_qp( |
| ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], |
| &ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out, |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.i8_frm_satd_act_accum_L0_frm_L1, |
| i_to_avg_rest_ratio); |
| |
| ihevce_set_L0_scd_qp( |
| ps_enc_ctxt->s_module_ctxt.apv_rc_ctxt[0], |
| i4_update_qp); |
| |
| if(ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_lap_out.i4_pic_type != IV_IDR_FRAME && |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_lap_out.i4_pic_type != IV_I_FRAME) |
| { |
| i4_update_qp += |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_lap_out.i4_temporal_lyr_id + |
| 1; |
| |
| i4_update_qp = |
| CLIP3(i4_update_qp, MIN_HEVC_QP, MAX_HEVC_QP); |
| } |
| |
| i4_count++; |
| if((i4_update_qp == |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.i4_L0_qp) || |
| i4_count > 4) |
| break; |
| |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.i4_L0_qp = i4_update_qp; |
| } |
| } |
| } |
| else |
| { |
| //i4_update_qp = ihevce_get_first_pass_qp(ps_enc_ctxt->s_multi_thrd.aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_lap_out.pv_frame_info); |
| i4_update_qp = ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_rc_lap_out.ps_frame_info->i4_rc_hevc_qp; |
| } |
| } |
| |
| { |
| WORD32 i4_index = 0; |
| rc_lap_out_params_t *ps_rc_lap_temp = |
| &ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_rc_lap_out; |
| WORD32 i4_offset; |
| |
| if(ps_rc_lap_temp->i4_rc_pic_type != IV_IDR_FRAME && |
| ps_rc_lap_temp->i4_rc_pic_type != IV_I_FRAME) |
| { |
| i4_index = ps_rc_lap_temp->i4_rc_temporal_lyr_id + 1; |
| } |
| i4_offset = ps_rc_lap_temp->ai4_offsets[i4_index]; |
| ASSERT(i4_offset >= 0); |
| /* Map the current frame Qp to L0 Qp */ |
| ps_rc_lap_temp->i4_L0_qp = i4_update_qp - i4_offset; |
| } |
| osal_mutex_unlock(ps_enc_ctxt->pv_rc_mutex_lock_hdl); |
| ASSERT(ps_multi_thrd->i4_qp_update_l0_ipe == -1); |
| ps_multi_thrd->i4_qp_update_l0_ipe = i4_update_qp; |
| ps_multi_thrd->i4_rc_l0_qp = i4_update_qp; |
| } |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_lap_out.f_i_pic_lamda_modifier = CONST_LAMDA_MOD_VAL; |
| } |
| /* update qp only if it is not scene cut since it has already been |
| populated in L1 for scene cut frames */ |
| if(1 == ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_input_buf.i4_inp_frm_data_valid_flag && |
| ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_rate_control_mode != 3) |
| { |
| /*get relevant lambda params*/ |
| ihevce_get_frame_lambda_prms( |
| ps_enc_ctxt, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx], |
| ps_multi_thrd->i4_qp_update_l0_ipe, |
| ps_enc_ctxt->s_runtime_src_prms.i4_field_pic, |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_lap_out.i4_is_ref_pic, |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_lap_out.i4_temporal_lyr_id, |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_lap_out.f_i_pic_lamda_modifier, |
| 0, |
| PRE_ENC_LAMBDA_TYPE); |
| |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx]->i4_curr_frm_qp = |
| ps_multi_thrd->i4_qp_update_l0_ipe; |
| } |
| /* Compute accumulated activity and strength */ |
| if(1 == ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_input_buf.i4_inp_frm_data_valid_flag && |
| ps_multi_thrd->ai4_num_thrds_processed_L0_ipe_qp_init[i4_cur_ipe_idx] == 0) |
| { |
| ihevce_variance_calc_acc_activity(ps_enc_ctxt, i4_cur_ipe_idx); |
| } |
| |
| /* Mark qp as read by last thread */ |
| ps_multi_thrd->ai4_num_thrds_processed_L0_ipe_qp_init[i4_cur_ipe_idx]++; |
| if(ps_multi_thrd->ai4_num_thrds_processed_L0_ipe_qp_init[i4_cur_ipe_idx] == |
| ps_multi_thrd->i4_num_pre_enc_proc_thrds) |
| { |
| ps_multi_thrd->ai4_num_thrds_processed_L0_ipe_qp_init[i4_cur_ipe_idx] = 0; |
| ps_multi_thrd->i4_qp_update_l0_ipe = -1; |
| } |
| |
| /****** UnLock the critical section after deinit ******/ |
| { |
| WORD32 i4_status; |
| i4_status = osal_mutex_unlock(ps_multi_thrd->pv_mutex_hdl_l0_ipe_init); |
| |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| if(1 == ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_input_buf.i4_inp_frm_data_valid_flag) |
| { |
| WORD32 i4_slice_type = |
| (WORD32)ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx] |
| ->s_slice_hdr.i1_slice_type; |
| WORD32 i4_quality_preset = |
| (WORD32)ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_lap_out.i4_quality_preset; |
| WORD32 i4_temporal_layer_id = |
| (WORD32)ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx] |
| ->s_lap_out.i4_temporal_lyr_id; |
| #if DISABLE_L0_IPE_INTRA_IN_BPICS |
| if(1 != ((i4_quality_preset == IHEVCE_QUALITY_P6) && |
| (i4_temporal_layer_id > TEMPORAL_LAYER_DISABLE))) |
| #endif |
| { |
| UWORD8 i1_cu_qp_delta_enabled_flag = |
| ps_enc_ctxt->ps_stat_prms->s_config_prms.i4_cu_level_rc; |
| |
| ihevce_populate_ipe_frame_init( |
| ps_enc_ctxt->s_module_ctxt.pv_ipe_ctxt, |
| ps_enc_ctxt->ps_stat_prms, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx]->i4_curr_frm_qp, |
| i4_slice_type, |
| i4_thrd_id, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx], |
| i1_cu_qp_delta_enabled_flag, |
| &ps_enc_ctxt->s_rc_quant, |
| i4_quality_preset, |
| i4_temporal_layer_id, |
| &ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx]->s_lap_out); |
| |
| ihevce_ipe_process( |
| ps_enc_ctxt->s_module_ctxt.pv_ipe_ctxt, |
| &ps_enc_ctxt->s_frm_ctb_prms, |
| &ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx]->as_lambda_prms[0], |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx], |
| ps_multi_thrd->ps_L0_IPE_curr_out_pre_enc, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx]->ps_ctb_analyse, |
| ps_multi_thrd->ps_L0_IPE_curr_out_pre_enc->ps_ipe_analyse_ctb, |
| &ps_enc_ctxt->s_multi_thrd, |
| i4_slice_type, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx]->ps_layer1_buf, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx]->ps_layer2_buf, |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx]->ps_ed_ctb_l1, |
| i4_thrd_id, |
| i4_cur_ipe_idx); |
| } |
| } |
| |
| /* ----------------------------------------------------------- */ |
| /* pre-enc de-init */ |
| /* ----------------------------------------------------------- */ |
| |
| /****** Lock the critical section for deinit ******/ |
| { |
| WORD32 i4_status; |
| i4_status = osal_mutex_lock(ps_multi_thrd->pv_mutex_hdl_pre_enc_deinit); |
| |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| ps_multi_thrd->ai4_num_thrds_processed_pre_enc[i4_cur_ipe_idx]++; |
| if(ps_multi_thrd->ai4_num_thrds_processed_pre_enc[i4_cur_ipe_idx] == |
| ps_multi_thrd->i4_num_pre_enc_proc_thrds) |
| { |
| ps_multi_thrd->ai4_pre_enc_deinit_done[i4_cur_ipe_idx] = 0; |
| ps_multi_thrd->ai4_num_thrds_processed_pre_enc[i4_cur_ipe_idx] = 0; |
| |
| /* reset the init flag so that init happens by the first thread for the |
| next frame of same ping_pnog instnace */ |
| ps_multi_thrd->ai4_pre_enc_init_done[i4_cur_ipe_idx] = 0; |
| } |
| |
| /* de-init */ |
| if(0 == ps_multi_thrd->ai4_pre_enc_deinit_done[i4_cur_ipe_idx]) |
| { |
| ihevce_lap_enc_buf_t *ps_curr_inp = |
| ps_multi_thrd->aps_curr_inp_pre_enc[i4_cur_ipe_idx]; |
| pre_enc_me_ctxt_t *ps_curr_out = |
| ps_multi_thrd->aps_curr_out_pre_enc[i4_cur_ipe_idx]; |
| |
| /* set the flag saying de init is done so that other cores dont do it */ |
| ps_multi_thrd->ai4_pre_enc_deinit_done[i4_cur_ipe_idx] = 1; |
| |
| if(1 == ps_curr_out->i4_frm_proc_valid_flag) |
| { |
| LWORD64 frame_acc_satd_by_modqp; |
| float L1_full_processed_ratio; |
| |
| if(ps_curr_inp->s_rc_lap_out.i8_satd_by_act_L1_accum_evaluated) |
| { |
| L1_full_processed_ratio = |
| ((float)ps_curr_inp->s_rc_lap_out.i8_frame_satd_by_act_L1_accum / |
| ps_curr_inp->s_rc_lap_out.i8_satd_by_act_L1_accum_evaluated); |
| } |
| else |
| { |
| L1_full_processed_ratio = 1.0; |
| } |
| /* Get frame-level satd cost and mode bit cost from IPE */ |
| ps_curr_out->i8_frame_acc_satd_cost = ihevce_ipe_get_frame_intra_satd_cost( |
| ps_enc_ctxt->s_module_ctxt.pv_ipe_ctxt, |
| &frame_acc_satd_by_modqp, |
| &ps_curr_inp->s_rc_lap_out.i8_est_I_pic_header_bits, |
| &ps_curr_inp->s_lap_out.i8_frame_level_activity_fact, |
| &ps_curr_inp->s_lap_out.i8_frame_l0_acc_satd); |
| |
| if((ps_curr_inp->s_lap_out.i4_quality_preset == IHEVCE_QUALITY_P6) && |
| (ps_curr_inp->s_lap_out.i4_temporal_lyr_id > TEMPORAL_LAYER_DISABLE)) |
| { |
| ps_curr_inp->s_rc_lap_out.i8_est_I_pic_header_bits = -1; |
| } |
| |
| { |
| WORD32 i4_cur_q_scale = (ps_enc_ctxt->s_rc_quant.pi4_qp_to_qscale |
| [ps_enc_ctxt->s_multi_thrd.i4_rc_l0_qp + |
| ps_enc_ctxt->s_rc_quant.i1_qp_offset] + |
| (1 << (QSCALE_Q_FAC_3 - 1))) >> |
| QSCALE_Q_FAC_3; |
| |
| /* calculate satd/act_fac = satd/qm * (qp_used_at_L0_analysis) */ |
| ps_curr_inp->s_rc_lap_out.i8_frame_satd_act_accum = |
| frame_acc_satd_by_modqp * i4_cur_q_scale; |
| } |
| |
| /* Because of early intra inter decision, L0 intra analysis might not happen for entire frame, correct the error |
| based on L1 data */ |
| ps_curr_inp->s_rc_lap_out.i8_est_I_pic_header_bits = (LWORD64)( |
| ps_curr_inp->s_rc_lap_out.i8_est_I_pic_header_bits * |
| L1_full_processed_ratio); |
| |
| if(L1_full_processed_ratio < 1.5) |
| { |
| ps_curr_inp->s_rc_lap_out.i8_frame_satd_act_accum = (LWORD64)( |
| ps_curr_inp->s_rc_lap_out.i8_frame_satd_act_accum * |
| L1_full_processed_ratio); |
| } |
| else |
| { |
| /* This is the case when too many candidates would not have gone through intra analysis, scaling based on L1 is found to be inappropriate, |
| Hence directly estimating L0 satd from L1 satd */ |
| ps_curr_inp->s_rc_lap_out.i8_frame_satd_act_accum = |
| ps_curr_inp->s_rc_lap_out.i8_frm_satd_act_accum_L0_frm_L1; |
| } |
| } |
| |
| /* register the current input buffer to be cnosumed by encode group threads */ |
| ps_curr_out->curr_inp_buf_id = |
| ps_multi_thrd->ai4_in_buf_id_pre_enc[i4_cur_ipe_idx]; |
| ps_curr_out->ps_curr_inp = ps_curr_inp; |
| |
| /* set the output buffer as produced */ |
| ihevce_q_set_buff_prod( |
| (void *)ps_enc_ctxt, |
| IHEVCE_PRE_ENC_ME_Q, |
| ps_multi_thrd->ai4_out_buf_id_pre_enc[i4_cur_ipe_idx]); |
| |
| /* set the output buffer of L0 IPE as produced */ |
| ihevce_q_set_buff_prod( |
| (void *)ps_enc_ctxt, |
| IHEVCE_L0_IPE_ENC_Q, |
| ps_multi_thrd->i4_L0_IPE_out_buf_id); |
| |
| /* update flag indicating ipe is done */ |
| ihevce_dmgr_update_frm_frm_sync(pv_dep_mngr_prev_frame_pre_enc_l0); |
| } |
| |
| { |
| /* index increment */ |
| i4_cur_ipe_idx = i4_cur_ipe_idx + 1; |
| |
| /* wrap around case */ |
| if(i4_cur_ipe_idx == (MAX_PRE_ENC_STAGGER + NUM_BUFS_DECOMP_HME)) |
| { |
| i4_cur_ipe_idx = 0; |
| } |
| i4_num_buf_prod_for_l0_ipe--; |
| } |
| /*NOTE: update of above indices should mark end if ipe.do not access below this*/ |
| |
| /****** UnLock the critical section after deinit ******/ |
| { |
| WORD32 i4_status; |
| i4_status = osal_mutex_unlock(ps_multi_thrd->pv_mutex_hdl_pre_enc_deinit); |
| |
| if(OSAL_SUCCESS != i4_status) |
| return 0; |
| } |
| |
| if(1 == ps_multi_thrd->i4_force_end_flag) |
| { |
| i4_end_flag = 1; |
| break; |
| } |
| } while((i4_end_flag || i4_out_flush_flag) && i4_num_buf_prod_for_l0_ipe); |
| } |
| } |
| if(i4_thrd_id == 0) |
| { |
| PROFILE_STOP(&ps_hle_ctxt->profile_pre_enc[i4_resolution_id], NULL); |
| } |
| |
| return 0; |
| } |
| |
| void calc_l1_level_hme_intra_sad_different_qp( |
| enc_ctxt_t *ps_enc_ctxt, |
| pre_enc_me_ctxt_t *ps_curr_out, |
| ihevce_lap_enc_buf_t *ps_curr_inp, |
| WORD32 i4_tot_ctb_l1_x, |
| WORD32 i4_tot_ctb_l1_y) |
| { |
| ihevce_ed_ctb_l1_t *ps_ed_ctb_l1; |
| WORD32 i4_qp_counter, i4_qp_start = 0, i4_qp_end = 0, i, i4_j, i4_new_frame_qp; |
| LWORD64 i8_l1_intra_sad_nc_accounted = 0, cur_intra_sad, raw_hme_sad = 0; |
| LWORD64 cur_hme_sad = 0, cur_hme_sad_for_offset = 0, acc_hme_l1_sad = 0, |
| acc_hme_l1_sad_for_offset = 0; |
| i4_qp_start = 1; |
| i4_qp_end = 51; |
| |
| for(i4_qp_counter = i4_qp_start; i4_qp_counter <= i4_qp_end; i4_qp_counter = i4_qp_counter + 3) |
| { |
| i8_l1_intra_sad_nc_accounted = 0; |
| cur_intra_sad = 0; |
| raw_hme_sad = 0; |
| cur_hme_sad = 0; |
| cur_hme_sad_for_offset = 0; |
| acc_hme_l1_sad = 0; |
| ps_ed_ctb_l1 = ps_curr_out->ps_ed_ctb_l1; |
| i4_new_frame_qp = i4_qp_counter; |
| acc_hme_l1_sad = 0; |
| |
| for(i = 0; i < (i4_tot_ctb_l1_x * i4_tot_ctb_l1_y); i += 1) |
| { |
| for(i4_j = 0; i4_j < 16; i4_j++) |
| { |
| if(ps_ed_ctb_l1->i4_best_sad_8x8_l1_ipe[i4_j] != -1) |
| { |
| ASSERT(ps_ed_ctb_l1->i4_best_sad_8x8_l1_ipe[i4_j] >= 0); |
| if(ps_curr_inp->s_rc_lap_out.i4_rc_pic_type != IV_I_FRAME && |
| ps_curr_inp->s_rc_lap_out.i4_rc_pic_type != IV_IDR_FRAME) |
| { |
| /*When l1 is disabled for B pics i4_best_sad_8x8_l1_ipe is set to max value always, |
| so will enter this path even for incomplete ctb, hence the assert holdsto good only for P pic */ |
| if(ps_curr_inp->s_rc_lap_out.i4_rc_quality_preset == IHEVCE_QUALITY_P6) |
| { |
| if(ps_curr_inp->s_rc_lap_out.i4_rc_pic_type == IV_P_FRAME) |
| { |
| ASSERT(ps_ed_ctb_l1->i4_best_sad_8x8_l1_me[i4_j] >= 0); |
| ASSERT(ps_ed_ctb_l1->i4_best_sad_8x8_l1_me_for_decide[i4_j] >= 0); |
| } |
| } |
| else |
| { |
| ASSERT(ps_ed_ctb_l1->i4_best_sad_8x8_l1_me[i4_j] >= 0); |
| ASSERT(ps_ed_ctb_l1->i4_best_sad_8x8_l1_me_for_decide[i4_j] >= 0); |
| } |
| |
| #if 1 //DISABLE_L1_L2_IPE_INTRA_IN_BPICS && RC_DEPENDENCY_FOR_BPIC |
| if((ps_ed_ctb_l1->i4_best_sad_8x8_l1_me[i4_j] != -1)) |
| #endif |
| { |
| cur_hme_sad = ps_ed_ctb_l1->i4_best_sad_8x8_l1_me[i4_j] - |
| (QP2QUANT_MD[i4_new_frame_qp] << 3); |
| } |
| raw_hme_sad += ps_ed_ctb_l1->i4_best_sad_8x8_l1_me[i4_j]; |
| |
| if(cur_hme_sad > 0) |
| acc_hme_l1_sad += cur_hme_sad; |
| } |
| if(cur_hme_sad_for_offset > 0) |
| { |
| acc_hme_l1_sad_for_offset += cur_hme_sad_for_offset; |
| } |
| ASSERT(ps_ed_ctb_l1->i4_best_sad_8x8_l1_ipe[i4_j] >= 0); |
| /*intra sad is scaled by 1.17 to be account for 1/3 vs 1/6th rounding*/ |
| cur_intra_sad = (LWORD64)( |
| (ps_ed_ctb_l1->i4_best_sad_8x8_l1_ipe[i4_j] * 1.17) - |
| (QP2QUANT_MD[i4_new_frame_qp] << 3)); |
| |
| if(cur_intra_sad > 0) |
| i8_l1_intra_sad_nc_accounted += cur_intra_sad; |
| } |
| } |
| ps_ed_ctb_l1 += 1; |
| } |
| if((ps_curr_inp->s_rc_lap_out.i4_rc_quality_preset == IHEVCE_QUALITY_P6) && |
| (ps_curr_inp->s_rc_lap_out.i4_rc_pic_type == IV_B_FRAME)) |
| { |
| ps_curr_inp->s_rc_lap_out.ai8_pre_intra_sad[i4_qp_counter] = -1; |
| ps_curr_inp->s_rc_lap_out.ai8_pre_intra_sad[i4_qp_counter + 1] = -1; |
| ps_curr_inp->s_rc_lap_out.ai8_pre_intra_sad[i4_qp_counter + 2] = -1; |
| } |
| else |
| { |
| ps_curr_inp->s_rc_lap_out.ai8_pre_intra_sad[i4_qp_counter] = |
| i8_l1_intra_sad_nc_accounted; |
| ps_curr_inp->s_rc_lap_out.ai8_pre_intra_sad[i4_qp_counter + 1] = |
| i8_l1_intra_sad_nc_accounted; |
| ps_curr_inp->s_rc_lap_out.ai8_pre_intra_sad[i4_qp_counter + 2] = |
| i8_l1_intra_sad_nc_accounted; |
| } |
| ps_curr_inp->s_rc_lap_out.ai8_frame_acc_coarse_me_sad[i4_qp_counter] = acc_hme_l1_sad; |
| ps_curr_inp->s_rc_lap_out.ai8_frame_acc_coarse_me_sad[i4_qp_counter + 1] = acc_hme_l1_sad; |
| ps_curr_inp->s_rc_lap_out.ai8_frame_acc_coarse_me_sad[i4_qp_counter + 2] = acc_hme_l1_sad; |
| ps_curr_inp->s_rc_lap_out.i8_raw_l1_coarse_me_sad = raw_hme_sad; |
| } |
| } |