/****************************************************************************** * * 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_plugin.c * * \brief * This file contains wrapper utilities to use hevc encoder library * * \date * 15/04/2014 * * \author * Ittiam * * List of Functions * * ****************************************************************************** */ /*****************************************************************************/ /* File Includes */ /*****************************************************************************/ /* System include files */ #include #include #include #include #include /* 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_macros.h" #include "ihevc_debug.h" #include "ihevc_structs.h" #include "ihevc_platform_macros.h" #include "ihevc_deblk.h" #include "ihevc_itrans_recon.h" #include "ihevc_chroma_itrans_recon.h" #include "ihevc_chroma_intra_pred.h" #include "ihevc_intra_pred.h" #include "ihevc_inter_pred.h" #include "ihevc_mem_fns.h" #include "ihevc_padding.h" #include "ihevc_weighted_pred.h" #include "ihevc_sao.h" #include "ihevc_resi_trans.h" #include "ihevc_quant_iquant_ssd.h" #include "ihevce_defs.h" #include "ihevce_lap_enc_structs.h" #include "ihevce_plugin.h" #include "ihevce_plugin_priv.h" #include "ihevce_hle_interface.h" #include "ihevce_multi_thrd_structs.h" #include "ihevce_me_common_defs.h" #include "ihevce_error_codes.h" #include "ihevce_error_checks.h" #include "ihevce_function_selector.h" #include "ihevce_enc_structs.h" #include "ihevce_global_tables.h" #include "cast_types.h" #include "osal.h" #include "osal_defaults.h" /*****************************************************************************/ /* Constant Macros */ /*****************************************************************************/ #define CREATE_TIME_ALLOCATION_INPUT 1 #define CREATE_TIME_ALLOCATION_OUTPUT 0 #define MAX_NUM_FRM_IN_GOP 600 /*****************************************************************************/ /* Extern variables */ /*****************************************************************************/ /*****************************************************************************/ /* Function Definitions */ /*****************************************************************************/ /*! ****************************************************************************** * \if Function name : mem_mngr_alloc \endif * * \brief * Memory manager specific alloc function * it expects to reset the allocated memory and provide the zero initialised * memory whenever this function getting called * * \param[in] pv_handle : handle to memory manager * (currently not required can be set to null) * \param[in] ps_memtab : memory descriptor pointer * * \return * Memory pointer * * \author * Ittiam * ***************************************************************************** */ void mem_mngr_alloc(void *pv_handle, ihevce_sys_api_t *ps_sys_api, iv_mem_rec_t *ps_memtab) { #ifndef X86_MINGW WORD32 error, mem_alignment; #endif (void)pv_handle; #ifdef X86_MINGW ps_memtab->pv_base = _aligned_malloc(ps_memtab->i4_mem_size, ps_memtab->i4_mem_alignment); #else mem_alignment = ps_memtab->i4_mem_alignment; mem_alignment = (mem_alignment >> 3) << 3; if(mem_alignment == 0) { error = posix_memalign(&ps_memtab->pv_base, sizeof(void *), ps_memtab->i4_mem_size); } else { error = posix_memalign(&ps_memtab->pv_base, mem_alignment, ps_memtab->i4_mem_size); } if(error != 0) { ps_sys_api->ihevce_printf(ps_sys_api->pv_cb_handle, "posix_memalign error %d\n", error); } #endif if(ps_memtab->pv_base == NULL) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Unable to allocate memory\n"); ASSERT(0); } else { memset(ps_memtab->pv_base, 0, ps_memtab->i4_mem_size); } return; } /*! ****************************************************************************** * \if Function name : memory_alloc \endif * * \brief * common memory allocate function should be used across all threads * it expects to reset the allocated memory and return the zero initialised * memory pointer whenever this function getting called * * \param[in] pv_handle : handle to memory manager * (currently not required can be set to null) * \param[in] u4_size : size of memory required * * \return * Memory pointer * * \author * Ittiam * ***************************************************************************** */ void *memory_alloc(void *pv_handle, UWORD32 u4_size) { (void)pv_handle; void *pv_buf = malloc(u4_size); if(pv_buf) { memset(pv_buf, 0, u4_size); } return (pv_buf); } /*! ****************************************************************************** * \if Function name : mem_mngr_free \endif * * \brief * Memory manager specific free function * * \param[in] pv_handle : handle to memory manager * (currently not required can be set to null) * \param[in] ps_memtab : memory descriptor pointer * * \return * Memory pointer * * \author * Ittiam * ***************************************************************************** */ void mem_mngr_free(void *pv_handle, iv_mem_rec_t *ps_memtab) { (void)pv_handle; #ifdef X86_MINGW _aligned_free(ps_memtab->pv_base); #else free(ps_memtab->pv_base); #endif return; } /*! ****************************************************************************** * \if Function name : memory_free \endif * * \brief * common memory free function should be used across all threads * * \param[in] pv_handle : handle to memory manager * (currently not required can be set to null) * \param[in] pv_mem : memory to be freed * * \return * Memory pointer * * \author * Ittiam * ***************************************************************************** */ void memory_free(void *pv_handle, void *pv_mem) { (void)pv_handle; free(pv_mem); return; } /*! ****************************************************************************** * \if Function name : ihevce_set_def_params \endif * * \brief * Set default values * * \param[in] Static params pointer * * \return * status * * \author * Ittiam * ***************************************************************************** */ IHEVCE_PLUGIN_STATUS_T ihevce_set_def_params(ihevce_static_cfg_params_t *ps_params) { WORD32 i, j; /* sanity checks */ if(NULL == ps_params) return (IHEVCE_EFAIL); memset(ps_params, 0, sizeof(*ps_params)); /* initialsie all the parameters to default values */ ps_params->i4_size = sizeof(ihevce_static_cfg_params_t); ps_params->i4_save_recon = 0; ps_params->i4_log_dump_level = 0; ps_params->i4_enable_logo = 0; ps_params->i4_enable_csv_dump = 0; /* Control to free the entropy output buffers */ /* 1 for non_blocking mode */ /* and 0 for blocking mode */ ps_params->i4_outbuf_buf_free_control = 1; /* coding tools parameters */ ps_params->s_coding_tools_prms.i4_size = sizeof(ihevce_coding_params_t); ps_params->s_coding_tools_prms.i4_cropping_mode = 1; ps_params->s_coding_tools_prms.i4_deblocking_type = 0; ps_params->s_coding_tools_prms.i4_enable_entropy_sync = 0; // New IDR/CDR Params ps_params->s_coding_tools_prms.i4_max_closed_gop_period = 0; ps_params->s_coding_tools_prms.i4_min_closed_gop_period = 0; ps_params->s_coding_tools_prms.i4_max_cra_open_gop_period = 60; ps_params->s_coding_tools_prms.i4_max_i_open_gop_period = 0; ps_params->s_coding_tools_prms.i4_max_reference_frames = -1; ps_params->s_coding_tools_prms.i4_max_temporal_layers = 0; ps_params->s_coding_tools_prms.i4_slice_type = 0; ps_params->s_coding_tools_prms.i4_use_default_sc_mtx = 0; ps_params->s_coding_tools_prms.i4_weighted_pred_enable = 0; ps_params->s_coding_tools_prms.i4_vqet = 0; ps_params->e_arch_type = ARCH_NA; /* config parameters */ ps_params->s_config_prms.i4_size = sizeof(ihevce_config_prms_t); ps_params->s_config_prms.i4_cu_level_rc = 1; ps_params->s_config_prms.i4_init_vbv_fullness = 0; ps_params->s_config_prms.i4_max_frame_qp = 51; ps_params->s_config_prms.i4_max_log2_cu_size = 6; ps_params->s_config_prms.i4_max_log2_tu_size = 5; ps_params->s_config_prms.i4_max_search_range_horz = 512; ps_params->s_config_prms.i4_max_search_range_vert = 256; ps_params->s_config_prms.i4_max_tr_tree_depth_I = 1; ps_params->s_config_prms.i4_max_tr_tree_depth_nI = 3; ps_params->s_config_prms.i4_min_frame_qp = 1; ps_params->s_config_prms.i4_min_log2_cu_size = 3; ps_params->s_config_prms.i4_min_log2_tu_size = 2; ps_params->s_config_prms.i4_num_frms_to_encode = -1; ps_params->s_config_prms.i4_rate_control_mode = 2; ps_params->s_config_prms.i4_stuffing_enable = 0; ps_params->s_config_prms.i4_vbr_max_peak_rate_dur = 2000; /* LAP parameters */ ps_params->s_lap_prms.i4_size = sizeof(ihevce_lap_params_t); ps_params->s_lap_prms.i4_deinterlacer_enable = 0; ps_params->s_lap_prms.i4_denoise_enable = 0; ps_params->s_lap_prms.i4_enable_wts_ofsts = 1; ps_params->s_lap_prms.i4_rc_look_ahead_pics = 0; /* Multi Thread parameters */ ps_params->s_multi_thrd_prms.i4_size = sizeof(ihevce_static_multi_thread_params_t); ps_params->s_multi_thrd_prms.i4_max_num_cores = 1; ps_params->s_multi_thrd_prms.i4_memory_alloc_ctrl_flag = 0; ps_params->s_multi_thrd_prms.i4_num_proc_groups = 1; ps_params->s_multi_thrd_prms.ai4_num_cores_per_grp[0] = -1; ps_params->s_multi_thrd_prms.i4_use_thrd_affinity = -1; //0; memset(&ps_params->s_multi_thrd_prms.au8_core_aff_mask[0], 0, sizeof(ULWORD64) * MAX_NUM_CORES); /* Output Streams parameters */ ps_params->s_out_strm_prms.i4_size = sizeof(ihevce_out_strm_params_t); ps_params->s_out_strm_prms.i4_aud_enable_flags = 0; ps_params->s_out_strm_prms.i4_eos_enable_flags = 0; ps_params->s_out_strm_prms.i4_codec_profile = 1; ps_params->s_out_strm_prms.i4_codec_tier = 0; ps_params->s_out_strm_prms.i4_codec_type = 0; #ifndef DISABLE_SEI ps_params->s_out_strm_prms.i4_sei_buffer_period_flags = 0; ps_params->s_out_strm_prms.i4_sei_enable_flag = 0; ps_params->s_out_strm_prms.i4_sei_payload_enable_flag = 0; ps_params->s_out_strm_prms.i4_sei_pic_timing_flags = 0; ps_params->s_out_strm_prms.i4_sei_cll_enable = 0; ps_params->s_out_strm_prms.u2_sei_avg_cll = 0; ps_params->s_out_strm_prms.u2_sei_max_cll = 0; ps_params->s_out_strm_prms.i4_sei_recovery_point_flags = 0; ps_params->s_out_strm_prms.i4_sei_mastering_disp_colour_vol_flags = 0; ps_params->s_out_strm_prms.i4_decoded_pic_hash_sei_flag = 0; #endif ps_params->s_out_strm_prms.i4_sps_at_cdr_enable = 1; ps_params->s_out_strm_prms.i4_vui_enable = 0; /*Set the interoperability flag to 0*/ ps_params->s_out_strm_prms.i4_interop_flags = 0; /* Source parameters */ ps_params->s_src_prms.i4_size = sizeof(ihevce_src_params_t); ps_params->s_src_prms.inp_chr_format = 1; ps_params->s_src_prms.i4_chr_format = 11; ps_params->s_src_prms.i4_field_pic = 0; ps_params->s_src_prms.i4_frm_rate_denom = 1000; ps_params->s_src_prms.i4_frm_rate_num = 30000; ps_params->s_src_prms.i4_height = 0; //1080; ps_params->s_src_prms.i4_input_bit_depth = 8; ps_params->s_src_prms.i4_topfield_first = 1; ps_params->s_src_prms.i4_width = 0; //1920; ps_params->s_src_prms.i4_orig_width = 0; ps_params->s_src_prms.i4_orig_height = 0; /* Target layer parameters */ ps_params->s_tgt_lyr_prms.i4_size = sizeof(ihevce_tgt_layer_params_t); ps_params->s_tgt_lyr_prms.i4_enable_temporal_scalability = 0; ps_params->s_tgt_lyr_prms.i4_internal_bit_depth = 8; ps_params->s_tgt_lyr_prms.i4_mbr_quality_setting = IHEVCE_MBR_HIGH_QUALITY; ps_params->s_tgt_lyr_prms.i4_multi_res_layer_reuse = 0; ps_params->s_tgt_lyr_prms.i4_num_res_layers = 1; ps_params->s_tgt_lyr_prms.i4_mres_single_out = 0; ps_params->s_tgt_lyr_prms.i4_start_res_id = 0; ps_params->s_tgt_lyr_prms.pf_scale_chroma = NULL; ps_params->s_tgt_lyr_prms.pf_scale_luma = NULL; ps_params->s_tgt_lyr_prms.pv_scaler_handle = NULL; /* target parameters */ for(i = 0; i < IHEVCE_MAX_NUM_RESOLUTIONS; i++) { ps_params->s_tgt_lyr_prms.as_tgt_params[i].i4_size = sizeof(ihevce_tgt_params_t); for(j = 0; j < IHEVCE_MAX_NUM_BITRATES; j++) { ps_params->s_tgt_lyr_prms.as_tgt_params[i].ai4_frame_qp[j] = 32; ps_params->s_tgt_lyr_prms.as_tgt_params[i].ai4_tgt_bitrate[j] = 5000000; ps_params->s_tgt_lyr_prms.as_tgt_params[i].ai4_peak_bitrate[j] = 10000000; ps_params->s_tgt_lyr_prms.as_tgt_params[i].ai4_max_vbv_buffer_size[j] = -1; } ps_params->s_tgt_lyr_prms.as_tgt_params[i].i4_codec_level = 156; ps_params->s_tgt_lyr_prms.as_tgt_params[i].i4_frm_rate_scale_factor = 1; ps_params->s_tgt_lyr_prms.as_tgt_params[i].i4_height = 0; ps_params->s_tgt_lyr_prms.as_tgt_params[i].i4_num_bitrate_instances = 1; ps_params->s_tgt_lyr_prms.as_tgt_params[i].i4_quality_preset = IHEVCE_QUALITY_P5; ps_params->s_tgt_lyr_prms.as_tgt_params[i].i4_width = 0; } /* SEI VUI parameters */ ps_params->s_vui_sei_prms.u1_aspect_ratio_info_present_flag = 0; ps_params->s_vui_sei_prms.au1_aspect_ratio_idc[0] = 255; ps_params->s_vui_sei_prms.au2_sar_width[0] = 4; ps_params->s_vui_sei_prms.au2_sar_height[0] = 3; ps_params->s_vui_sei_prms.u1_overscan_info_present_flag = 0; ps_params->s_vui_sei_prms.u1_overscan_appropriate_flag = 0; ps_params->s_vui_sei_prms.u1_video_signal_type_present_flag = 1; ps_params->s_vui_sei_prms.u1_video_format = 5; ps_params->s_vui_sei_prms.u1_video_full_range_flag = 1; ps_params->s_vui_sei_prms.u1_colour_description_present_flag = 0; ps_params->s_vui_sei_prms.u1_colour_primaries = 2; ps_params->s_vui_sei_prms.u1_transfer_characteristics = 2; ps_params->s_vui_sei_prms.u1_matrix_coefficients = 2; ps_params->s_vui_sei_prms.u1_chroma_loc_info_present_flag = 0; ps_params->s_vui_sei_prms.u1_chroma_sample_loc_type_top_field = 0; ps_params->s_vui_sei_prms.u1_chroma_sample_loc_type_bottom_field = 0; ps_params->s_vui_sei_prms.u1_vui_hrd_parameters_present_flag = 0; ps_params->s_vui_sei_prms.u1_timing_info_present_flag = 0; ps_params->s_vui_sei_prms.u1_nal_hrd_parameters_present_flag = 0; /* Setting sysAPIs to NULL */ memset(&ps_params->s_sys_api, 0, sizeof(ihevce_sys_api_t)); /* Multi pass parameters */ memset(&ps_params->s_pass_prms, 0, sizeof(ihevce_pass_prms_t)); ps_params->s_pass_prms.i4_size = sizeof(ihevce_pass_prms_t); /* Tile parameters */ ps_params->s_app_tile_params.i4_size = sizeof(ihevce_app_tile_params_t); ps_params->s_app_tile_params.i4_tiles_enabled_flag = 0; ps_params->s_app_tile_params.i4_uniform_spacing_flag = 1; ps_params->s_app_tile_params.i4_num_tile_cols = 1; ps_params->s_app_tile_params.i4_num_tile_rows = 1; ps_params->s_slice_params.i4_slice_segment_mode = 0; ps_params->s_slice_params.i4_slice_segment_argument = 1300; return (IHEVCE_EOK); } /*! ****************************************************************************** * \if Function name : ihevce_cmds_error_report \endif * * \brief * Call back from encoder to report errors * * \param[in] pv_error_handling_cb_handle * \param[in] i4_error_code * \param[in] i4_cmd_type * \param[in] i4_id * * \return * None * * \author * Ittiam * ***************************************************************************** */ IV_API_CALL_STATUS_T ihevce_cmds_error_report( void *pv_cb_handle, WORD32 i4_error_code, WORD32 i4_cmd_type, WORD32 i4_buf_id) { /*local variables*/ plugin_ctxt_t *plugin_ctxt = (plugin_ctxt_t *)pv_cb_handle; ihevce_static_cfg_params_t *ps_static_cfg_params = ((ihevce_hle_ctxt_t *)plugin_ctxt->pv_hle_interface_ctxt)->ps_static_cfg_prms; if(i4_cmd_type == 0) ps_static_cfg_params->s_sys_api.ihevce_printf( ps_static_cfg_params->s_sys_api.pv_cb_handle, "PLUGIN ERROR: Asynchronous Buffer Error %d in Buffer Id %d", i4_error_code, i4_buf_id); else ps_static_cfg_params->s_sys_api.ihevce_printf( ps_static_cfg_params->s_sys_api.pv_cb_handle, "PLUGIN ERROR: Synchronous Buffer Error %d in Buffer Id %d", i4_error_code, i4_buf_id); return (IV_SUCCESS); } /*! ****************************************************************************** * \if Function name : ihevce_strm_fill_done \endif * * \brief * Call back from encoder when Bitstream is ready to consume * * \param[in] * \param[in] * \param[in] * * \return * None * * \author * Ittiam * ***************************************************************************** */ IV_API_CALL_STATUS_T ihevce_strm_fill_done(void *pv_ctxt, void *pv_curr_out, WORD32 i4_br_id, WORD32 i4_res_id) { /* local variables */ plugin_ctxt_t *ps_ctxt = (plugin_ctxt_t *)pv_ctxt; app_ctxt_t *ps_app_ctxt = &ps_ctxt->s_app_ctxt; out_strm_prms_t *ps_out_strm_prms = &ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id]; void *pv_app_out_strm_buf_mutex_hdl = ps_out_strm_prms->pv_app_out_strm_buf_mutex_hdl; void *pv_app_out_strm_buf_cond_var_hdl = ps_out_strm_prms->pv_app_out_strm_buf_cond_var_hdl; iv_output_data_buffs_t *ps_curr_out = (iv_output_data_buffs_t *)pv_curr_out; WORD32 end_flag = ps_curr_out->i4_end_flag; WORD32 osal_result; /* ------ output dump stream -- */ if((WORD32)IV_FAIL != ps_curr_out->i4_process_ret_sts) { if(0 != ps_curr_out->i4_bytes_generated) { /* accumulate the total bits generated */ (ps_out_strm_prms->u8_total_bits) += ps_curr_out->i4_bytes_generated * 8; (ps_out_strm_prms->u4_num_frms_enc)++; } } /****** Lock the critical section ******/ osal_result = osal_mutex_lock(pv_app_out_strm_buf_mutex_hdl); if(OSAL_SUCCESS != osal_result) return (IV_FAIL); /* Update the end flag to communicate with the o/p thread */ ps_app_ctxt->ai4_out_strm_end_flag[i4_res_id][i4_br_id] = end_flag; /* set the produced status of the buffer */ { WORD32 idx = ps_curr_out->i4_cb_buf_id; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][idx].i4_timestamp_low = ps_curr_out->i4_out_timestamp_low; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][idx].i4_timestamp_high = ps_curr_out->i4_out_timestamp_high; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][idx].i4_bytes_gen = ps_curr_out->i4_bytes_generated; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][idx].i4_is_key_frame = 0; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][idx].i4_end_flag = end_flag; if((IV_IDR_FRAME == ps_curr_out->i4_encoded_frame_type) || (IV_I_FRAME == ps_curr_out->i4_encoded_frame_type)) { ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][idx].i4_is_key_frame = 1; } /* set the buffer as produced */ ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][idx].i4_is_prod = 1; } /****** Wake ******/ osal_cond_var_signal(pv_app_out_strm_buf_cond_var_hdl); /****** Unlock the critical section ******/ osal_result = osal_mutex_unlock(pv_app_out_strm_buf_mutex_hdl); if(OSAL_SUCCESS != osal_result) return (IV_FAIL); return (IV_SUCCESS); } /*! ****************************************************************************** * \if Function name : ihevce_plugin_init \endif * * \brief * Initialises the encoder context and threads * * \param[in] Static params pointer * * \return * status * * \author * Ittiam * ***************************************************************************** */ IHEVCE_PLUGIN_STATUS_T ihevce_init(ihevce_static_cfg_params_t *ps_params, void **ppv_ihevce_hdl) { /* local variables */ plugin_ctxt_t *ps_ctxt; app_ctxt_t *ps_app_ctxt; ihevce_hle_ctxt_t *ps_interface_ctxt; ihevce_sys_api_t *ps_sys_api; osal_cb_funcs_t s_cb_funcs; WORD32 status = 0; /* sanity checks */ if(NULL == ps_params) return (IHEVCE_EFAIL); if(NULL == ppv_ihevce_hdl) return (IHEVCE_EFAIL); /* set the handle to null by default */ *ppv_ihevce_hdl = NULL; /* Initiallizing system apis */ ps_sys_api = &ps_params->s_sys_api; ihevce_init_sys_api(NULL, ps_sys_api); /* --------------------------------------------------------------------- */ /* Query and print Encoder version */ /* --------------------------------------------------------------------- */ ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "Encoder version %s\n\n", ihevce_get_encoder_version()); /* --------------------------------------------------------------------- */ /* Plugin Handle create */ /* --------------------------------------------------------------------- */ ps_ctxt = (plugin_ctxt_t *)memory_alloc(NULL, sizeof(plugin_ctxt_t)); if(NULL == ps_ctxt) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in Plugin initialization\n"); return (IHEVCE_EFAIL); } /* initialise memory call backs */ ps_ctxt->ihevce_mem_alloc = memory_alloc; ps_ctxt->ihevce_mem_free = memory_free; ps_ctxt->u8_num_frames_encoded = 0; if((0 == ps_params->i4_res_id) && (0 == ps_params->i4_br_id)) { /* --------------------------------------------------------------------- */ /* OSAL Handle create */ /* --------------------------------------------------------------------- */ ps_ctxt->pv_osal_handle = memory_alloc(NULL, OSAL_HANDLE_SIZE); /* Initialize OSAL call back functions */ s_cb_funcs.mmr_handle = NULL; s_cb_funcs.osal_alloc = memory_alloc; s_cb_funcs.osal_free = memory_free; status = osal_init(ps_ctxt->pv_osal_handle); if(OSAL_SUCCESS != status) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in OSAL initialization\n"); return (IHEVCE_EFAIL); } status = osal_register_callbacks(ps_ctxt->pv_osal_handle, &s_cb_funcs); if(OSAL_SUCCESS != status) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in OSAL call back registration\n"); return (IHEVCE_EFAIL); } /* --------------------------------------------------------------------- */ /* Thread affinity Initialization */ /* --------------------------------------------------------------------- */ if(ps_params->s_multi_thrd_prms.i4_use_thrd_affinity) { WORD32 i4_ctr; /* loop over all the cores */ for(i4_ctr = 0; i4_ctr < ps_params->s_multi_thrd_prms.i4_max_num_cores; i4_ctr++) { /* All cores are logical cores */ ps_params->s_multi_thrd_prms.au8_core_aff_mask[i4_ctr] = ((ULWORD64)1 << i4_ctr); } } /* --------------------------------------------------------------------- */ /* Context Initialization */ /* --------------------------------------------------------------------- */ ps_app_ctxt = &ps_ctxt->s_app_ctxt; ps_ctxt->ps_static_cfg_prms = (ihevce_static_cfg_params_t *)ps_ctxt->ihevce_mem_alloc( NULL, sizeof(ihevce_static_cfg_params_t)); if(NULL == ps_ctxt->ps_static_cfg_prms) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in Plugin memory initialization\n"); return (IHEVCE_EFAIL); } ps_params->apF_csv_file[0][0] = NULL; /* set the memory manager handle to NULL */ ps_app_ctxt->pv_mem_mngr_handle = NULL; /* --------------------------------------------------------------------- */ /* Back up the static params passed by caller */ /* --------------------------------------------------------------------- */ memcpy(ps_ctxt->ps_static_cfg_prms, ps_params, sizeof(ihevce_static_cfg_params_t)); ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_orig_width = ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_width; if(HEVCE_MIN_WIDTH > ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_width) { ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_width = HEVCE_MIN_WIDTH; } ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_orig_height = ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_height; if(HEVCE_MIN_HEIGHT > ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_height) { ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_height = HEVCE_MIN_HEIGHT; } /* setting tgt width and height same as src width and height */ ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.as_tgt_params[0].i4_width = ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_width; ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.as_tgt_params[0].i4_height = ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_height; /* setting key frame interval */ ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_closed_gop_period = MIN(MAX_NUM_FRM_IN_GOP, ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_closed_gop_period); ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_cra_open_gop_period = MIN(MAX_NUM_FRM_IN_GOP, ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_cra_open_gop_period); ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_i_open_gop_period = MIN(MAX_NUM_FRM_IN_GOP, ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_i_open_gop_period); /* entropy sync is disabled if there is only one CTB row */ if(ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_height <= (1 << ps_ctxt->ps_static_cfg_prms->s_config_prms.i4_max_log2_cu_size)) { ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_enable_entropy_sync = 0; } /* --------------------------------------------------------------------- */ /* High Level Encoder context init */ /* --------------------------------------------------------------------- */ ps_interface_ctxt = (ihevce_hle_ctxt_t *)ps_ctxt->ihevce_mem_alloc(NULL, sizeof(ihevce_hle_ctxt_t)); if(NULL == ps_interface_ctxt) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in Plugin HLE memory initialization\n"); return (IHEVCE_EFAIL); } ps_interface_ctxt->i4_size = sizeof(ihevce_hle_ctxt_t); ps_ctxt->pv_hle_interface_ctxt = ps_interface_ctxt; /* store the static config parameters pointer */ ps_interface_ctxt->ps_static_cfg_prms = ps_ctxt->ps_static_cfg_prms; /* initialise the interface strucure parameters */ ps_interface_ctxt->pv_inp_cb_handle = (void *)ps_ctxt; ps_interface_ctxt->pv_out_cb_handle = (void *)ps_ctxt; ps_interface_ctxt->pv_recon_cb_handle = (void *)ps_ctxt; ps_interface_ctxt->pv_osal_handle = ps_ctxt->pv_osal_handle; ps_interface_ctxt->ihevce_mem_alloc = mem_mngr_alloc; ps_interface_ctxt->ihevce_mem_free = mem_mngr_free; ps_interface_ctxt->i4_hle_init_done = 0; ps_interface_ctxt->pv_mem_mgr_hdl = ps_app_ctxt->pv_mem_mngr_handle; /* reigter the callbacks */ ps_interface_ctxt->ihevce_output_strm_fill_done = ihevce_strm_fill_done; ps_interface_ctxt->ihevce_output_recon_fill_done = NULL; ps_interface_ctxt->ihevce_set_free_input_buff = NULL; /*Added for run time or create time creation*/ ps_interface_ctxt->i4_create_time_input_allocation = (WORD32)CREATE_TIME_ALLOCATION_INPUT; ps_interface_ctxt->i4_create_time_output_allocation = (WORD32)CREATE_TIME_ALLOCATION_OUTPUT; ps_interface_ctxt->ihevce_cmds_error_report = ihevce_cmds_error_report; ps_interface_ctxt->pv_cmd_err_cb_handle = (void *)ps_ctxt; /* --------------------------------------------------------------------- */ /* High Level Encoder Instance Creation */ /* --------------------------------------------------------------------- */ status = ihevce_hle_interface_create(ps_interface_ctxt); if((WORD32)IV_FAIL == status) { ihevce_hle_interface_delete(ps_interface_ctxt); memory_free(NULL, ps_interface_ctxt); /* free static config memory */ ps_ctxt->ihevce_mem_free(NULL, ps_ctxt->ps_static_cfg_prms); /* free osal handle */ memory_free(NULL, ps_ctxt->pv_osal_handle); /* free plugin ctxt memory */ memory_free(NULL, ps_ctxt); ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in Plugin HLE create failed\n"); return (IHEVCE_EFAIL); } /* --------------------------------------------------------------------- */ /* Input Output and Command buffer allocation */ /* --------------------------------------------------------------------- */ { WORD32 ctr; WORD32 buf_size; UWORD8 *pu1_tmp_buf; WORD32 i4_res_id; WORD32 i4_br_id; WORD32 i4_num_resolutions; WORD32 ai4_num_bitrate_instances[IHEVCE_MAX_NUM_RESOLUTIONS] = { 1 }; iv_input_bufs_req_t s_input_bufs_req; iv_res_layer_output_bufs_req_t s_res_layer_output_bufs_req; iv_res_layer_recon_bufs_req_t s_res_layer_recon_bufs_req; /* local array of pointers */ void *apv_inp_luma_bufs[MAX_NUM_INP_DATA_BUFS]; void *apv_inp_cb_bufs[MAX_NUM_INP_DATA_BUFS]; void *apv_inp_cr_bufs[MAX_NUM_INP_DATA_BUFS]; void *apv_inp_sync_bufs[MAX_NUM_INP_CTRL_SYNC_BUFS]; void *apv_inp_async_bufs[MAX_NUM_INP_CTRL_ASYNC_BUFS]; void *apv_out_data_bufs[IHEVCE_MAX_NUM_RESOLUTIONS][IHEVCE_MAX_NUM_BITRATES] [MAX_NUM_OUT_DATA_BUFS]; /* get the number of resolutions */ i4_num_resolutions = ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.i4_num_res_layers; /* set the size of the structure */ s_input_bufs_req.i4_size = sizeof(iv_input_bufs_req_t); s_res_layer_output_bufs_req.i4_size = sizeof(iv_res_layer_output_bufs_req_t); s_res_layer_recon_bufs_req.i4_size = sizeof(iv_res_layer_recon_bufs_req_t); /* loop over num resolutions */ for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { /* store the number of bitrates */ ai4_num_bitrate_instances[i4_res_id] = ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.as_tgt_params[i4_res_id] .i4_num_bitrate_instances; /* loop over num bitrates */ for(i4_br_id = 0; i4_br_id < ai4_num_bitrate_instances[i4_res_id]; i4_br_id++) { s_res_layer_output_bufs_req.s_output_buf_req[i4_res_id][i4_br_id].i4_size = sizeof(iv_output_bufs_req_t); } } /* call Query I/O buffer */ status = ihevce_query_io_buf_req( ps_interface_ctxt, &s_input_bufs_req, &s_res_layer_output_bufs_req, &s_res_layer_recon_bufs_req); /* check on the requirements against the MAX of application */ /* should be present only for debug purpose */ /* --------------- Input data buffers init ---------------------- */ /* allocate memory for input buffers */ if(ps_interface_ctxt->i4_create_time_input_allocation == 1) { buf_size = s_input_bufs_req.i4_min_size_uv_buf + s_input_bufs_req.i4_min_size_y_buf; ps_ctxt->s_memtab_inp_data_buf.i4_size = sizeof(iv_mem_rec_t); ps_ctxt->s_memtab_inp_data_buf.i4_mem_alignment = 4; ps_ctxt->s_memtab_inp_data_buf.i4_mem_size = (s_input_bufs_req.i4_min_num_yuv_bufs + XTRA_INP_DATA_BUFS) * buf_size; ps_ctxt->s_memtab_inp_data_buf.e_mem_type = IV_EXT_CACHEABLE_NUMA_NODE0_MEM; mem_mngr_alloc( ps_app_ctxt->pv_mem_mngr_handle, ps_sys_api, &ps_ctxt->s_memtab_inp_data_buf); pu1_tmp_buf = (UWORD8 *)ps_ctxt->s_memtab_inp_data_buf.pv_base; if(NULL == pu1_tmp_buf) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in allocate memory\n"); return (IHEVCE_EFAIL); } /* loop to initialise the buffer pointer */ for(ctr = 0; ctr < s_input_bufs_req.i4_min_num_yuv_bufs + XTRA_INP_DATA_BUFS; ctr++) { apv_inp_luma_bufs[ctr] = pu1_tmp_buf; apv_inp_cb_bufs[ctr] = pu1_tmp_buf + s_input_bufs_req.i4_min_size_y_buf; apv_inp_cr_bufs[ctr] = NULL; /* 420SP case */ /* increment the input buffer pointer to next buffer */ pu1_tmp_buf += buf_size; } } /* --------------- Output data buffers init ---------------------- */ /* loop over num resolutions */ for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { for(i4_br_id = 0; i4_br_id < ai4_num_bitrate_instances[i4_res_id]; i4_br_id++) { buf_size = s_res_layer_output_bufs_req.s_output_buf_req[i4_res_id][i4_br_id] .i4_min_size_bitstream_buf; ps_ctxt->as_memtab_out_data_buf[i4_res_id][i4_br_id].i4_size = sizeof(iv_mem_rec_t); ps_ctxt->as_memtab_out_data_buf[i4_res_id][i4_br_id].i4_mem_alignment = 4; if(!ps_interface_ctxt->i4_create_time_output_allocation) { ps_ctxt->as_memtab_out_data_buf[i4_res_id][i4_br_id].i4_mem_size = (s_res_layer_output_bufs_req.s_output_buf_req[i4_res_id][i4_br_id] .i4_min_num_out_bufs + XTRA_OUT_DATA_BUFS) * buf_size; } else { ps_ctxt->as_memtab_out_data_buf[i4_res_id][i4_br_id].i4_mem_size = (s_res_layer_output_bufs_req.s_output_buf_req[i4_res_id][i4_br_id] .i4_min_num_out_bufs) * buf_size; } ps_ctxt->as_memtab_out_data_buf[i4_res_id][i4_br_id].e_mem_type = IV_EXT_CACHEABLE_NUMA_NODE1_MEM; mem_mngr_alloc( ps_app_ctxt->pv_mem_mngr_handle, ps_sys_api, &ps_ctxt->as_memtab_out_data_buf[i4_res_id][i4_br_id]); pu1_tmp_buf = (UWORD8 *)ps_ctxt->as_memtab_out_data_buf[i4_res_id][i4_br_id].pv_base; if(NULL == pu1_tmp_buf) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in allocate memory\n"); return (IHEVCE_EFAIL); } if(ps_interface_ctxt->i4_create_time_output_allocation == 1) { /* loop to initialise the buffer pointer */ for(ctr = 0; ctr < s_res_layer_output_bufs_req.s_output_buf_req[i4_res_id][i4_br_id] .i4_min_num_out_bufs; ctr++) { apv_out_data_bufs[i4_res_id][i4_br_id][ctr] = pu1_tmp_buf; pu1_tmp_buf += buf_size; } } else { WORD32 i4_num_out_bufs = s_res_layer_output_bufs_req.s_output_buf_req[i4_res_id][i4_br_id] .i4_min_num_out_bufs + XTRA_OUT_DATA_BUFS; ps_ctxt->i4_num_out_bufs = i4_num_out_bufs; ps_ctxt->ai4_free_out_buf_idx[i4_res_id][i4_br_id] = 0; ps_ctxt->i4_prod_out_buf_idx = 0; /* Assert to make sure ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][] array has more bufs than ps_ctxt->i4_num_out_bufs. Needed to identify wrap-around case */ ASSERT(ps_ctxt->i4_num_out_bufs <= MAX_NUM_OUT_DATA_BUFS); /* loop to initialise the buffer pointer */ for(ctr = 0; ctr < i4_num_out_bufs; ctr++) { ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][ctr].i4_idx = ctr; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][ctr].i4_is_free = 1; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][ctr].i4_is_prod = 0; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][ctr].i4_bytes_gen = 0; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][ctr].pu1_buf = pu1_tmp_buf; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][ctr].i4_buf_size = buf_size; pu1_tmp_buf += buf_size; } } /* create mutex for controlling the out strm buf b/w appln and encoder */ ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_mutex_hdl = osal_mutex_create(ps_ctxt->pv_osal_handle); if(NULL == ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_mutex_hdl) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in Plugin initialization\n"); return (IHEVCE_EFAIL); } /* create mutex for controlling the out strm buf b/w appln and encoder */ ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_cond_var_hdl = osal_cond_var_create(ps_ctxt->pv_osal_handle); if(NULL == ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_cond_var_hdl) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in Plugin initialization\n"); return (IHEVCE_EFAIL); } } } if(ps_interface_ctxt->i4_create_time_input_allocation == 1) { /* ------------- Input sync command buffers init -------------------- */ buf_size = s_input_bufs_req.i4_min_size_synch_ctrl_bufs; ps_ctxt->s_memtab_inp_sync_ctrl_buf.i4_size = sizeof(iv_mem_rec_t); ps_ctxt->s_memtab_inp_sync_ctrl_buf.i4_mem_alignment = 4; ps_ctxt->s_memtab_inp_sync_ctrl_buf.i4_mem_size = (s_input_bufs_req.i4_min_num_yuv_bufs + XTRA_INP_DATA_BUFS) * buf_size; ps_ctxt->s_memtab_inp_sync_ctrl_buf.e_mem_type = IV_EXT_CACHEABLE_NUMA_NODE0_MEM; mem_mngr_alloc( ps_app_ctxt->pv_mem_mngr_handle, ps_sys_api, &ps_ctxt->s_memtab_inp_sync_ctrl_buf); pu1_tmp_buf = (UWORD8 *)ps_ctxt->s_memtab_inp_sync_ctrl_buf.pv_base; if(NULL == pu1_tmp_buf) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in allocate memory\n"); return (IHEVCE_EFAIL); } /* loop to initialise the buffer pointer */ for(ctr = 0; ctr < s_input_bufs_req.i4_min_num_yuv_bufs + XTRA_INP_DATA_BUFS; ctr++) { apv_inp_sync_bufs[ctr] = pu1_tmp_buf; pu1_tmp_buf += buf_size; } } /* ------------- Input async command buffers init -------------------- */ buf_size = s_input_bufs_req.i4_min_size_asynch_ctrl_bufs; /* allocate memory for output status buffer */ ps_ctxt->pu1_inp_async_ctrl_buf = (UWORD8 *)ps_ctxt->ihevce_mem_alloc( NULL, s_input_bufs_req.i4_min_num_asynch_ctrl_bufs * buf_size); if(ps_ctxt->pu1_inp_async_ctrl_buf == NULL) { ps_sys_api->ihevce_printf( ps_sys_api->pv_cb_handle, "IHEVCE ERROR: Error in Plugin memory initialization\n"); return (IHEVCE_EFAIL); } pu1_tmp_buf = ps_ctxt->pu1_inp_async_ctrl_buf; /* loop to initialise the buffer pointer */ for(ctr = 0; ctr < s_input_bufs_req.i4_min_num_asynch_ctrl_bufs; ctr++) { apv_inp_async_bufs[ctr] = pu1_tmp_buf; pu1_tmp_buf += buf_size; } /* Create IO ports for the buffer allocated */ { iv_input_data_ctrl_buffs_desc_t s_inp_desc; iv_input_asynch_ctrl_buffs_desc_t s_inp_ctrl_desc; iv_res_layer_output_data_buffs_desc_t s_mres_out_desc; iv_res_layer_recon_data_buffs_desc_t s_mres_recon_desc; /* set the parameters of the input data control desc */ s_inp_desc.i4_size = sizeof(iv_input_data_ctrl_buffs_desc_t); s_inp_desc.i4_num_synch_ctrl_bufs = s_input_bufs_req.i4_min_num_synch_ctrl_bufs; s_inp_desc.i4_num_yuv_bufs = s_input_bufs_req.i4_min_num_yuv_bufs + XTRA_INP_DATA_BUFS; s_inp_desc.i4_size_y_buf = s_input_bufs_req.i4_min_size_y_buf; s_inp_desc.i4_size_uv_buf = s_input_bufs_req.i4_min_size_uv_buf; s_inp_desc.i4_size_synch_ctrl_bufs = s_input_bufs_req.i4_min_size_synch_ctrl_bufs; s_inp_desc.ppv_synch_ctrl_bufs = &apv_inp_sync_bufs[0]; s_inp_desc.ppv_y_buf = &apv_inp_luma_bufs[0]; s_inp_desc.ppv_u_buf = &apv_inp_cb_bufs[0]; s_inp_desc.ppv_v_buf = &apv_inp_cr_bufs[0]; /* set the parameters of the input async control desc */ s_inp_ctrl_desc.i4_size = sizeof(iv_input_asynch_ctrl_buffs_desc_t); s_inp_ctrl_desc.i4_num_asynch_ctrl_bufs = s_input_bufs_req.i4_min_num_asynch_ctrl_bufs; s_inp_ctrl_desc.i4_size_asynch_ctrl_bufs = s_input_bufs_req.i4_min_size_asynch_ctrl_bufs; s_inp_ctrl_desc.ppv_asynch_ctrl_bufs = &apv_inp_async_bufs[0]; for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { /* set the parameters of the output data desc */ for(i4_br_id = 0; i4_br_id < ai4_num_bitrate_instances[i4_res_id]; i4_br_id++) { s_mres_out_desc.s_output_data_buffs[i4_res_id][i4_br_id].i4_size = sizeof(iv_output_data_buffs_desc_t); if(!ps_interface_ctxt->i4_create_time_output_allocation) { s_mres_out_desc.s_output_data_buffs[i4_res_id][i4_br_id] .i4_num_bitstream_bufs = s_res_layer_output_bufs_req.s_output_buf_req[i4_res_id][i4_br_id] .i4_min_num_out_bufs + XTRA_OUT_DATA_BUFS; } else { s_mres_out_desc.s_output_data_buffs[i4_res_id][i4_br_id] .i4_num_bitstream_bufs = s_res_layer_output_bufs_req.s_output_buf_req[i4_res_id][i4_br_id] .i4_min_num_out_bufs; } s_mres_out_desc.s_output_data_buffs[i4_res_id][i4_br_id] .i4_size_bitstream_buf = s_res_layer_output_bufs_req.s_output_buf_req[i4_res_id][i4_br_id] .i4_min_size_bitstream_buf; s_mres_out_desc.s_output_data_buffs[i4_res_id][i4_br_id].ppv_bitstream_bufs = &apv_out_data_bufs[i4_res_id][i4_br_id][0]; } } s_mres_recon_desc.i4_size = sizeof(iv_res_layer_recon_data_buffs_desc_t); /* call create I/O ports */ status = ihevce_create_ports( ps_interface_ctxt, &s_inp_desc, &s_inp_ctrl_desc, &s_mres_out_desc, &s_mres_recon_desc); } } /* --------------------------------------------------------------------- */ /* Create a High level encoder thread */ /* --------------------------------------------------------------------- */ { osal_thread_attr_t s_thread_attr = OSAL_DEFAULT_THREAD_ATTR; /* Initialize application thread attributes */ s_thread_attr.exit_code = 0; s_thread_attr.name = 0; s_thread_attr.priority_map_flag = 1; s_thread_attr.priority = OSAL_PRIORITY_DEFAULT; s_thread_attr.stack_addr = 0; s_thread_attr.stack_size = THREAD_STACK_SIZE; s_thread_attr.thread_func = ihevce_hle_interface_thrd; s_thread_attr.thread_param = (void *)(ps_interface_ctxt); s_thread_attr.core_affinity_mask = 0; s_thread_attr.group_num = 0; /* Create High level encoder thread */ ps_ctxt->pv_hle_thread_hdl = osal_thread_create(ps_ctxt->pv_osal_handle, &s_thread_attr); if(NULL == ps_ctxt->pv_hle_thread_hdl) { return IHEVCE_EFAIL; } } /* --------------------------------------------------------------------- */ /* Wait until HLE init is done */ /* --------------------------------------------------------------------- */ { volatile WORD32 hle_init_done; volatile WORD32 *pi4_hle_init_done; pi4_hle_init_done = (volatile WORD32 *)&ps_interface_ctxt->i4_hle_init_done; do { hle_init_done = *pi4_hle_init_done; } while(0 == hle_init_done); } /* reset flush mode */ ps_ctxt->i4_flush_mode_on = 0; { WORD32 i4_res_id; WORD32 i4_br_id; for(i4_res_id = 0; i4_res_id < IHEVCE_MAX_NUM_RESOLUTIONS; i4_res_id++) { for(i4_br_id = 0; i4_br_id < IHEVCE_MAX_NUM_BITRATES; i4_br_id++) { /* reset out end flag */ ps_ctxt->ai4_out_end_flag[i4_res_id][i4_br_id] = 0; } } } /* reset the field id */ ps_ctxt->i4_field_id = 0; /* based on number of B pics set the DTS value */ ps_ctxt->i8_dts = -1; if(0 != ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_temporal_layers) { ps_ctxt->i8_dts = (-1) * (1 << ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_temporal_layers); } /* initialsie the buffer stride */ { WORD32 max_cu_size; max_cu_size = (1 << ps_ctxt->ps_static_cfg_prms->s_config_prms.i4_max_log2_cu_size); ps_ctxt->i4_frm_stride = ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_width + SET_CTB_ALIGN(ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_width, max_cu_size); } } else { /* free plugin ctxt memory */ memory_free(NULL, ps_ctxt); return (IHEVCE_EFAIL); } /* reset the place holders of old bitrate */ memset(&ps_ctxt->ai4_old_bitrate[0][0], 0, sizeof(ps_ctxt->ai4_old_bitrate)); ps_ctxt->ai4_old_bitrate[0][0] = ps_params->s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0]; /* store the plugin handle before returning */ *ppv_ihevce_hdl = (void *)ps_ctxt; return (IHEVCE_EOK); } static IHEVCE_PLUGIN_STATUS_T ihevce_receive_out_buffer(plugin_ctxt_t *ps_ctxt, ihevce_out_buf_t *ps_out) { app_ctxt_t *ps_app_ctxt = &ps_ctxt->s_app_ctxt; WORD32 i4_res_id, i4_br_id; WORD32 i4_num_resolutions; WORD32 ai4_num_bitrate_instances[IHEVCE_MAX_NUM_RESOLUTIONS] = { 1 }; i4_num_resolutions = ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.i4_num_res_layers; for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { ai4_num_bitrate_instances[i4_res_id] = ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.as_tgt_params[i4_res_id] .i4_num_bitrate_instances; } /* default init */ ps_out->pu1_output_buf = NULL; ps_out->i4_bytes_generated = 0; /* ---------------- if any output buffer is available return the buffer back ------------- */ while(1) { WORD32 osal_result; WORD32 buf_present = 0; WORD32 i4_is_prod = 1; WORD32 i4_atleast_one_br_prod = 0; /****** Lock the critical section ******/ osal_result = osal_mutex_lock(ps_app_ctxt->as_out_strm_prms[0][0].pv_app_out_strm_buf_mutex_hdl); if(OSAL_SUCCESS != osal_result) return IHEVCE_EFAIL; /* wait until entropy sends an output */ while(1) { i4_is_prod = 1; for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { for(i4_br_id = 0; i4_br_id < ai4_num_bitrate_instances[i4_res_id]; i4_br_id++) { i4_is_prod &= ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][ps_ctxt->i4_prod_out_buf_idx] .i4_is_prod; i4_atleast_one_br_prod |= ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][ps_ctxt->i4_prod_out_buf_idx] .i4_is_prod; } } if(!i4_is_prod) { for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { for(i4_br_id = 0; i4_br_id < ai4_num_bitrate_instances[i4_res_id]; i4_br_id++) { osal_cond_var_wait( ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_cond_var_hdl, ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_mutex_hdl); } } } else { break; } } ASSERT(i4_is_prod == 1); /* check if the current buffer for all bitrates and resolutions have been produced */ if(1 == i4_is_prod) { buf_present = 1; for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { for(i4_br_id = 0; i4_br_id < ai4_num_bitrate_instances[i4_res_id]; i4_br_id++) { /* set the buffer to free status */ ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][ps_ctxt->i4_prod_out_buf_idx] .i4_is_free = 1; if((0 == i4_res_id) && (0 == i4_br_id)) { ps_out->i4_bytes_generated = ps_ctxt->aaas_out_bufs[0][0][ps_ctxt->i4_prod_out_buf_idx].i4_bytes_gen; ps_out->pu1_output_buf = ps_ctxt->aaas_out_bufs[0][0][ps_ctxt->i4_prod_out_buf_idx].pu1_buf; } } } /* copy the contents to output buffer */ ps_out->i4_is_key_frame = ps_ctxt->aaas_out_bufs[0][0][ps_ctxt->i4_prod_out_buf_idx].i4_is_key_frame; ps_out->u8_pts = ps_ctxt->aaas_out_bufs[0][0][ps_ctxt->i4_prod_out_buf_idx].i4_timestamp_low; ps_out->u8_pts = ps_out->u8_pts | ((ULWORD64)( ps_ctxt->aaas_out_bufs[0][0][ps_ctxt->i4_prod_out_buf_idx].i4_timestamp_high) << 32); ps_out->i4_end_flag = ps_ctxt->aaas_out_bufs[0][0][ps_ctxt->i4_prod_out_buf_idx].i4_end_flag; ps_out->i8_dts = ps_ctxt->i8_dts; /* increment the DTS */ ps_ctxt->i8_dts++; } /* check for buffer present */ if(1 == buf_present) { ps_ctxt->i4_prod_out_buf_idx++; /* wrap around case */ if(ps_ctxt->i4_prod_out_buf_idx == ps_ctxt->i4_num_out_bufs) { ps_ctxt->i4_prod_out_buf_idx = 0; } /****** Unlock the critical section ******/ osal_result = osal_mutex_unlock( ps_app_ctxt->as_out_strm_prms[0][0].pv_app_out_strm_buf_mutex_hdl); if(OSAL_SUCCESS != osal_result) return IHEVCE_EFAIL; /* break while 1 loop */ break; } else { /* in steady state*/ if(0 == ps_ctxt->i4_flush_mode_on) { /****** Unlock the critical section ******/ osal_result = osal_mutex_unlock( ps_app_ctxt->as_out_strm_prms[0][0].pv_app_out_strm_buf_mutex_hdl); if(OSAL_SUCCESS != osal_result) return IHEVCE_EFAIL; if(!i4_atleast_one_br_prod) /*** If atleast one bitrate is produced do not break from loop **/ { /*** Continue in while loop and Wait for next bitrate ***/ /* break while 1 loop */ break; } } else { /* In flush mode is ON then this function must return output buffers. Otherwise assume that encoding is over and return fail */ /****** Unlock the critical section ******/ osal_result = osal_mutex_unlock( ps_app_ctxt->as_out_strm_prms[0][0].pv_app_out_strm_buf_mutex_hdl); if(OSAL_SUCCESS != osal_result) return IHEVCE_EFAIL; } } } return IHEVCE_EOK; } static IHEVCE_PLUGIN_STATUS_T ihevce_queue_out_buffer(plugin_ctxt_t *ps_ctxt, WORD32 i4_res_id, WORD32 i4_br_id) { app_ctxt_t *ps_app_ctxt = &ps_ctxt->s_app_ctxt; ihevce_hle_ctxt_t *ps_interface_ctxt = (ihevce_hle_ctxt_t *)ps_ctxt->pv_hle_interface_ctxt; /* --------------------------------------------------------------------- */ /* Free Output buffer Queuing */ /* --------------------------------------------------------------------- */ /* ------- Que in free output buffer if end flag is not set ------ */ if(0 == ps_ctxt->ai4_out_end_flag[i4_res_id][i4_br_id]) { WORD32 osal_result; iv_output_data_buffs_t *ps_curr_out; WORD32 buf_id_strm; WORD32 free_idx; free_idx = ps_ctxt->ai4_free_out_buf_idx[i4_res_id][i4_br_id]; if(1 == ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][free_idx].i4_is_free) { /* ---------- get a free desc. from output Q ------ */ ps_curr_out = (iv_output_data_buffs_t *)ihevce_q_get_free_out_strm_buff( ps_interface_ctxt, &buf_id_strm, BUFF_QUE_NON_BLOCKING_MODE, i4_br_id, i4_res_id); /* if a free buffer is available */ if(NULL != ps_curr_out) { /****** Lock the critical section ******/ osal_result = osal_mutex_lock(ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_mutex_hdl); if(OSAL_SUCCESS != osal_result) return IHEVCE_EFAIL; if(1 == ps_app_ctxt->ai4_out_strm_end_flag[i4_res_id][i4_br_id]) { ps_curr_out->i4_is_last_buf = 1; ps_ctxt->ai4_out_end_flag[i4_res_id][i4_br_id] = 1; } else { ps_curr_out->i4_is_last_buf = 0; } ASSERT(ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][free_idx].i4_is_free == 1); ASSERT(free_idx == ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][free_idx].i4_idx); ps_curr_out->pv_bitstream_bufs = (void *)ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][free_idx].pu1_buf; ps_curr_out->i4_cb_buf_id = ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][free_idx].i4_idx; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][free_idx].i4_is_free = 0; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][free_idx].i4_is_prod = 0; ps_ctxt->aaas_out_bufs[i4_res_id][i4_br_id][free_idx].i4_bytes_gen = 0; ps_ctxt->ai4_free_out_buf_idx[i4_res_id][i4_br_id]++; /* wrap around case */ if(ps_ctxt->ai4_free_out_buf_idx[i4_res_id][i4_br_id] == ps_ctxt->i4_num_out_bufs) { ps_ctxt->ai4_free_out_buf_idx[i4_res_id][i4_br_id] = 0; } /****** Unlock the critical section ******/ osal_result = osal_mutex_unlock(ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_mutex_hdl); if(OSAL_SUCCESS != osal_result) return IHEVCE_EFAIL; /* ---------- set the buffer as produced ---------- */ ihevce_q_set_out_strm_buff_prod( ps_interface_ctxt, buf_id_strm, i4_br_id, i4_res_id); } } } return IHEVCE_EOK; } /*! ****************************************************************************** * \if Function name : ihevce_close \endif * * \brief * De-Initialises the encoder context and threads * * \param[in] Static params pointer * * \return * status * * \author * Ittiam * ***************************************************************************** */ IHEVCE_PLUGIN_STATUS_T ihevce_close(void *pv_ihevce_hdl) { /* local variables */ plugin_ctxt_t *ps_ctxt; app_ctxt_t *ps_app_ctxt; ihevce_hle_ctxt_t *ps_interface_ctxt; WORD32 i4_num_resolutions; WORD32 i4_res_id; WORD32 i4_br_id; WORD32 ai4_num_bitrate_instances[IHEVCE_MAX_NUM_RESOLUTIONS] = { 1 }; ihevce_sys_api_t *ps_sys_api; /* sanity checks */ if(NULL == pv_ihevce_hdl) return (IHEVCE_EFAIL); /* derive local variables */ ps_ctxt = (plugin_ctxt_t *)pv_ihevce_hdl; ps_sys_api = &ps_ctxt->ps_static_cfg_prms->s_sys_api; if((0 == ps_ctxt->ps_static_cfg_prms->i4_res_id) && (0 == ps_ctxt->ps_static_cfg_prms->i4_br_id)) { ps_interface_ctxt = (ihevce_hle_ctxt_t *)ps_ctxt->pv_hle_interface_ctxt; ps_app_ctxt = &ps_ctxt->s_app_ctxt; i4_num_resolutions = ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.i4_num_res_layers; if(1 != ps_ctxt->i4_flush_mode_on) { for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { ai4_num_bitrate_instances[i4_res_id] = ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.as_tgt_params[i4_res_id] .i4_num_bitrate_instances; for(i4_br_id = 0; i4_br_id < ai4_num_bitrate_instances[i4_res_id]; i4_br_id++) { /* ------- Que in free output buffer if end flag is not set ------ */ ihevce_queue_out_buffer(ps_ctxt, i4_res_id, i4_br_id); } } /* --------------------------------------------------------------------- */ /* Input Processing */ /* --------------------------------------------------------------------- */ { WORD32 buf_id; iv_input_data_ctrl_buffs_t *ps_curr_inp; WORD32 *pi4_ctrl_ptr; /* ---------- get a free buffer from input Q ------ */ ps_curr_inp = (iv_input_data_ctrl_buffs_t *)ihevce_q_get_free_inp_data_buff( ps_interface_ctxt, &buf_id, BUFF_QUE_BLOCKING_MODE); if(NULL != ps_curr_inp) { /* flush mode command */ ps_curr_inp->i4_buf_id = buf_id; /* set the input status to invalid flag */ ps_curr_inp->i4_inp_frm_data_valid_flag = 0; pi4_ctrl_ptr = (WORD32 *)ps_curr_inp->pv_synch_ctrl_bufs; *pi4_ctrl_ptr = IHEVCE_SYNCH_API_FLUSH_TAG; *(pi4_ctrl_ptr + 1) = 0; *(pi4_ctrl_ptr + 2) = IHEVCE_SYNCH_API_END_TAG; ps_curr_inp->i4_cmd_buf_size = 4 * 3; /* 4 bytes */ /* ---------- set the buffer as produced ---------- */ ihevce_q_set_inp_data_buff_prod(ps_interface_ctxt, buf_id); } else { /* Enable flush-mode and internal-flush once limit according to Eval-version is reached */ ps_ctxt->i4_flush_mode_on = 1; } } } /* --------------------------------------------------------------------- */ /* Wait and destroy Processing threads */ /* --------------------------------------------------------------------- */ /* Wait for High level encoder thread to complete */ osal_thread_wait(ps_ctxt->pv_hle_thread_hdl); /* Destroy Hle thread */ osal_thread_destroy(ps_ctxt->pv_hle_thread_hdl); /* --------------------------------------------------------------------- */ /* Input Output and Command buffers free */ /* --------------------------------------------------------------------- */ /* free output data and control buffer */ for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { ai4_num_bitrate_instances[i4_res_id] = ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.as_tgt_params[i4_res_id] .i4_num_bitrate_instances; for(i4_br_id = 0; i4_br_id < ai4_num_bitrate_instances[i4_res_id]; i4_br_id++) { mem_mngr_free( ps_app_ctxt->pv_mem_mngr_handle, &ps_ctxt->as_memtab_out_data_buf[i4_res_id][i4_br_id]); /* free mutex of out strm buf b/w appln and encoder */ osal_mutex_destroy(ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_mutex_hdl); osal_cond_var_destroy(ps_app_ctxt->as_out_strm_prms[i4_res_id][i4_br_id] .pv_app_out_strm_buf_cond_var_hdl); } } ps_ctxt->ihevce_mem_free(NULL, ps_ctxt->pu1_out_ctrl_buf); ps_ctxt->ihevce_mem_free(NULL, ps_ctxt->pu1_inp_async_ctrl_buf); /* free input data and control buffer */ if(ps_interface_ctxt->i4_create_time_input_allocation == 1) { mem_mngr_free(ps_app_ctxt->pv_mem_mngr_handle, &ps_ctxt->s_memtab_inp_data_buf); mem_mngr_free(ps_app_ctxt->pv_mem_mngr_handle, &ps_ctxt->s_memtab_inp_sync_ctrl_buf); } /* --------------------------------------------------------------------- */ /* Encoder Instance Deletion */ /* --------------------------------------------------------------------- */ ihevce_hle_interface_delete(ps_interface_ctxt); /* free the high level encoder context memory */ ps_ctxt->ihevce_mem_free(NULL, ps_ctxt->pv_hle_interface_ctxt); if(ps_ctxt->ps_static_cfg_prms->i4_enable_csv_dump) { ps_sys_api->s_file_io_api.ihevce_fclose( (void *)ps_sys_api->pv_cb_handle, ps_ctxt->ps_static_cfg_prms->apF_csv_file[0][0]); } /* free static config memory */ ps_ctxt->ihevce_mem_free(NULL, ps_ctxt->ps_static_cfg_prms); /* free osal handle */ memory_free(NULL, ps_ctxt->pv_osal_handle); /* free plugin ctxt memory */ memory_free(NULL, pv_ihevce_hdl); } else { return (IHEVCE_EFAIL); } return (IHEVCE_EOK); } /*! ****************************************************************************** * \if Function name : ihevce_copy_inp_8bit \endif * * \brief * Input copy function for 8 bit input * * \param[in] Source and desdtination buffer descriptors * * \return * None * * \author * Ittiam * ***************************************************************************** */ IV_API_CALL_STATUS_T ihevce_copy_inp_8bit( iv_input_data_ctrl_buffs_t *ps_curr_inp, ihevce_inp_buf_t *ps_inp, WORD32 chroma_format, WORD32 i4_orig_wd, WORD32 i4_orig_ht) { UWORD8 *pu1_src, *pu1_dst; WORD32 src_strd, dst_strd; WORD32 frm_height = i4_orig_ht; WORD32 frm_width = i4_orig_wd; WORD32 buf_height = ps_curr_inp->s_input_buf.i4_y_ht; WORD32 buf_width = ps_curr_inp->s_input_buf.i4_y_wd; WORD32 rows, cols; pu1_src = (UWORD8 *)ps_inp->apv_inp_planes[0]; src_strd = ps_inp->ai4_inp_strd[0]; pu1_dst = (UWORD8 *)ps_curr_inp->s_input_buf.pv_y_buf; dst_strd = ps_curr_inp->s_input_buf.i4_y_strd; if((ps_inp->ai4_inp_size[0] < (src_strd * frm_height)) || (ps_inp->ai4_inp_size[0] <= 0) || (ps_inp->apv_inp_planes[0] == NULL)) { return (IV_FAIL); } /* copy the input luma data into internal buffer */ for(rows = 0; rows < frm_height; rows++) { memcpy(pu1_dst, pu1_src, frm_width); if(buf_width > frm_width) { memset(pu1_dst + frm_width, 0x0, buf_width - frm_width); } pu1_src += src_strd; pu1_dst += dst_strd; } while(rows < buf_height) { memset(pu1_dst, 0x0, buf_width); pu1_dst += dst_strd; rows++; } if(IV_YUV_420P == chroma_format) { UWORD8 *pu1_src_u, *pu1_src_v; WORD32 src_strd_u, src_strd_v; pu1_src_u = (UWORD8 *)ps_inp->apv_inp_planes[1]; src_strd_u = ps_inp->ai4_inp_strd[1]; pu1_src_v = (UWORD8 *)ps_inp->apv_inp_planes[2]; src_strd_v = ps_inp->ai4_inp_strd[2]; pu1_dst = (UWORD8 *)ps_curr_inp->s_input_buf.pv_u_buf; dst_strd = ps_curr_inp->s_input_buf.i4_uv_strd; frm_width = i4_orig_wd >> 1; frm_height = i4_orig_ht >> 1; buf_width = ps_curr_inp->s_input_buf.i4_uv_wd; buf_height = ps_curr_inp->s_input_buf.i4_uv_ht; if((ps_inp->ai4_inp_size[1] < (ps_inp->ai4_inp_strd[1] * frm_height)) || (ps_inp->ai4_inp_size[1] <= 0) || (pu1_src_u == NULL)) { return (IV_FAIL); } if((ps_inp->ai4_inp_size[2] < (ps_inp->ai4_inp_strd[2] * frm_height)) || (ps_inp->ai4_inp_size[2] <= 0) || (pu1_src_v == NULL)) { return (IV_FAIL); } /* copy the input chroma data in pixel interleaved format */ for(rows = 0; rows < frm_height; rows++) { for(cols = 0; cols < frm_width; cols++) { /* U V alternate */ pu1_dst[(cols << 1)] = pu1_src_u[cols]; pu1_dst[(cols << 1) + 1] = pu1_src_v[cols]; } if(buf_width > (cols << 1)) { memset(&pu1_dst[(cols << 1)], 0x80, buf_width - (cols << 1)); } pu1_src_u += src_strd_u; pu1_src_v += src_strd_v; pu1_dst += dst_strd; } while(rows < buf_height) { memset(pu1_dst, 0x80, buf_width); pu1_dst += dst_strd; rows++; } } else if(IV_YUV_420SP_UV == chroma_format) { pu1_src = (UWORD8 *)ps_inp->apv_inp_planes[1]; src_strd = ps_inp->ai4_inp_strd[1]; pu1_dst = (UWORD8 *)ps_curr_inp->s_input_buf.pv_u_buf; dst_strd = ps_curr_inp->s_input_buf.i4_uv_strd; frm_width = i4_orig_wd; frm_height = i4_orig_ht >> 1; buf_width = ps_curr_inp->s_input_buf.i4_uv_wd; buf_height = ps_curr_inp->s_input_buf.i4_uv_ht; if((ps_inp->ai4_inp_size[1] < (ps_inp->ai4_inp_strd[1] * frm_height)) || (ps_inp->ai4_inp_size[1] <= 0) || (pu1_src == NULL)) { return (IV_FAIL); } /* copy the input luma data into internal buffer */ for(rows = 0; rows < frm_height; rows++) { memcpy(pu1_dst, pu1_src, frm_width); if(buf_width > frm_width) { memset(pu1_dst + frm_width, 0x80, buf_width - frm_width); } pu1_src += src_strd; pu1_dst += dst_strd; } while(rows < buf_height) { memset(pu1_dst, 0x80, buf_width); pu1_dst += dst_strd; rows++; } } return (IV_SUCCESS); } /*! ****************************************************************************** * \if Function name : ihevce_encode_header \endif * * \brief * Receive sps, pps and vps of the encoded sequence * * \param[in] Plugin handle, Output buffer * * \return * Success or Failure * * \author * Ittiam * ***************************************************************************** */ IHEVCE_PLUGIN_STATUS_T ihevce_encode_header(void *pv_ihevce_hdl, ihevce_out_buf_t *ps_out) { plugin_ctxt_t *ps_ctxt = (plugin_ctxt_t *)pv_ihevce_hdl; ihevce_hle_ctxt_t *ps_interface_ctxt; /* sanity checks */ if(NULL == pv_ihevce_hdl) return (IHEVCE_EFAIL); if(NULL == ps_out) return (IHEVCE_EFAIL); if((0 == ps_ctxt->ps_static_cfg_prms->i4_res_id) && (0 == ps_ctxt->ps_static_cfg_prms->i4_br_id)) { WORD32 status; /* ------- Que in free output buffer if end flag is not set ------ */ ihevce_queue_out_buffer(ps_ctxt, 0, 0); /* ------- API call to encoder header ------- */ ps_interface_ctxt = (ihevce_hle_ctxt_t *)ps_ctxt->pv_hle_interface_ctxt; status = ihevce_entropy_encode_header(ps_interface_ctxt, 0, 0); if(status) return IHEVCE_EFAIL; /* ------- receive header ------- */ ihevce_receive_out_buffer(ps_ctxt, ps_out); } else { return (IHEVCE_EFAIL); } return (IHEVCE_EOK); } /*! ****************************************************************************** * \if Function name : ihevce_encode \endif * * \brief * Frame level processing function * * \param[in] Plugin handle, Input buffer, Output buffer * * \return * Success or Failure * * \author * Ittiam * ***************************************************************************** */ IHEVCE_PLUGIN_STATUS_T ihevce_encode(void *pv_ihevce_hdl, ihevce_inp_buf_t *ps_inp, ihevce_out_buf_t *ps_out) { /* local variables */ plugin_ctxt_t *ps_ctxt; app_ctxt_t *ps_app_ctxt; ihevce_hle_ctxt_t *ps_interface_ctxt; WORD32 i4_res_id, i4_br_id; WORD32 i4_num_resolutions; WORD32 ai4_num_bitrate_instances[IHEVCE_MAX_NUM_RESOLUTIONS] = { 1 }; UWORD32 u4_latency = 0; /* sanity checks */ if(NULL == pv_ihevce_hdl) return (IHEVCE_EFAIL); if(NULL == ps_out) return (IHEVCE_EFAIL); /* derive local variables */ ps_ctxt = (plugin_ctxt_t *)pv_ihevce_hdl; if((0 == ps_ctxt->ps_static_cfg_prms->i4_res_id) && (0 == ps_ctxt->ps_static_cfg_prms->i4_br_id)) { ps_interface_ctxt = (ihevce_hle_ctxt_t *)ps_ctxt->pv_hle_interface_ctxt; ps_app_ctxt = &ps_ctxt->s_app_ctxt; i4_num_resolutions = ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.i4_num_res_layers; if(ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_temporal_layers) { u4_latency += (1 << ps_ctxt->ps_static_cfg_prms->s_coding_tools_prms.i4_max_temporal_layers) - 1; } u4_latency += ps_ctxt->ps_static_cfg_prms->s_lap_prms.i4_rc_look_ahead_pics; /* Once the internal-flush-flag has been set and codec has issued end flag, exit encoding by returning IHEVCE_EFAIL */ if(ps_ctxt->i4_internal_flush) { if(1 == ps_app_ctxt->ai4_out_strm_end_flag[0][0]) return (IHEVCE_EFAIL); } for(i4_res_id = 0; i4_res_id < i4_num_resolutions; i4_res_id++) { ai4_num_bitrate_instances[i4_res_id] = ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.as_tgt_params[i4_res_id] .i4_num_bitrate_instances; for(i4_br_id = 0; i4_br_id < ai4_num_bitrate_instances[i4_res_id]; i4_br_id++) { /* ------- Que in free output buffer if end flag is not set ------ */ ihevce_queue_out_buffer(ps_ctxt, i4_res_id, i4_br_id); } } /* --------------------------------------------------------------------- */ /* Input Processing */ /* --------------------------------------------------------------------- */ if(0 == ps_ctxt->i4_flush_mode_on) { WORD32 frm_stride; WORD32 frm_width; WORD32 frm_height; WORD32 buf_id; iv_input_data_ctrl_buffs_t *ps_curr_inp; WORD32 *pi4_ctrl_ptr; frm_width = ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_width; frm_height = ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_height; frm_stride = ps_ctxt->i4_frm_stride; /* ---------- get a free buffer from input Q ------ */ ps_curr_inp = (iv_input_data_ctrl_buffs_t *)ihevce_q_get_free_inp_data_buff( ps_interface_ctxt, &buf_id, BUFF_QUE_BLOCKING_MODE); if(NULL != ps_curr_inp) { /* if input buffer is not NULL */ if(NULL != ps_inp) { WORD32 result; pi4_ctrl_ptr = (WORD32 *)ps_curr_inp->pv_synch_ctrl_bufs; /* ---------- set ip params ---------- */ ps_curr_inp->s_input_buf.i4_size = sizeof(iv_yuv_buf_t); ps_curr_inp->s_input_buf.i4_y_wd = frm_width; ps_curr_inp->s_input_buf.i4_y_ht = frm_height; ps_curr_inp->s_input_buf.i4_y_strd = frm_stride; ps_curr_inp->s_input_buf.i4_uv_wd = frm_width; ps_curr_inp->s_input_buf.i4_uv_ht = frm_height >> ((ps_ctxt->ps_static_cfg_prms->s_src_prms.inp_chr_format == 13) ? 0 : 1); ps_curr_inp->s_input_buf.i4_uv_strd = frm_stride; ps_curr_inp->i4_buf_id = buf_id; ps_curr_inp->i4_inp_frm_data_valid_flag = 1; ps_curr_inp->i4_topfield_first = 1; /* set to default */ ps_curr_inp->i4_bottom_field = ps_ctxt->i4_field_id; ps_curr_inp->i4_inp_timestamp_low = (WORD32)(ps_inp->u8_pts & 0xFFFFFFFF); ps_curr_inp->i4_inp_timestamp_high = (WORD32)(ps_inp->u8_pts >> 32); /* toggle field id */ ps_ctxt->i4_field_id = !ps_ctxt->i4_field_id; /* ---------- Introduction of Force IDR locs ---------- */ if(ps_inp->i4_force_idr_flag) { *pi4_ctrl_ptr = IHEVCE_SYNCH_API_FORCE_IDR_TAG; *(pi4_ctrl_ptr + 1) = 0; pi4_ctrl_ptr += 2; /* set the cmd to NA */ *pi4_ctrl_ptr = IHEVCE_SYNCH_API_END_TAG; ps_curr_inp->i4_cmd_buf_size = 4 * 3; /* 12 bytes */ } else { /* set the cmd to NA */ *pi4_ctrl_ptr = IHEVCE_SYNCH_API_END_TAG; ps_curr_inp->i4_cmd_buf_size = 4; /* 4 bytes */ } /* call the input copy function */ result = ihevce_copy_inp_8bit( ps_curr_inp, ps_inp, ps_ctxt->ps_static_cfg_prms->s_src_prms.inp_chr_format, ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_orig_width, ps_ctxt->ps_static_cfg_prms->s_src_prms.i4_orig_height); if(IV_SUCCESS != result) return (IHEVCE_EFAIL); if(3 != ps_ctxt->ps_static_cfg_prms->s_config_prms.i4_rate_control_mode) { /* Dynamic Change in bitrate not supported for multi res/MBR */ /*** Check for change in bitrate command ***/ if(ps_ctxt->ai4_old_bitrate[0][0] != ps_inp->i4_curr_bitrate) { WORD32 buf_id; WORD32 *pi4_cmd_buf; iv_input_ctrl_buffs_t *ps_ctrl_buf; ihevce_dyn_config_prms_t *ps_dyn_br; WORD32 codec_level_index = ihevce_get_level_index( ps_ctxt->ps_static_cfg_prms->s_tgt_lyr_prms.as_tgt_params[0] .i4_codec_level); WORD32 max_bitrate = g_as_level_data[codec_level_index].i4_max_bit_rate [ps_ctxt->ps_static_cfg_prms->s_out_strm_prms.i4_codec_tier] * 1000; /* ---------- get a free buffer from command Q ------ */ ps_ctrl_buf = (iv_input_ctrl_buffs_t *)ihevce_q_get_free_inp_ctrl_buff( ps_interface_ctxt, &buf_id, BUFF_QUE_BLOCKING_MODE); /* store the buffer id */ ps_ctrl_buf->i4_buf_id = buf_id; /* get the buffer pointer */ pi4_cmd_buf = (WORD32 *)ps_ctrl_buf->pv_asynch_ctrl_bufs; /* store the set default command, encoder should use create time prms */ *pi4_cmd_buf = IHEVCE_ASYNCH_API_SETBITRATE_TAG; *(pi4_cmd_buf + 1) = sizeof(ihevce_dyn_config_prms_t); ps_dyn_br = (ihevce_dyn_config_prms_t *)(pi4_cmd_buf + 2); ps_dyn_br->i4_size = sizeof(ihevce_dyn_config_prms_t); ps_dyn_br->i4_tgt_br_id = 0; ps_dyn_br->i4_tgt_res_id = 0; ps_dyn_br->i4_new_tgt_bitrate = MIN(ps_inp->i4_curr_bitrate, max_bitrate); ps_dyn_br->i4_new_tgt_bitrate = MAX(ps_dyn_br->i4_new_tgt_bitrate, MIN_BITRATE); ps_dyn_br->i4_new_peak_bitrate = MIN((ps_dyn_br->i4_new_tgt_bitrate << 1), max_bitrate); pi4_cmd_buf += 2; pi4_cmd_buf += (sizeof(ihevce_dyn_config_prms_t) >> 2); *(pi4_cmd_buf) = IHEVCE_ASYNCH_API_END_TAG; ps_ctrl_buf->i4_cmd_buf_size = 12 + sizeof(ihevce_dyn_config_prms_t); /* ---------- set the buffer as produced ---------- */ ihevce_q_set_inp_ctrl_buff_prod(ps_interface_ctxt, buf_id); ps_ctxt->ai4_old_bitrate[0][0] = ps_dyn_br->i4_new_tgt_bitrate; } } ps_ctxt->u8_num_frames_queued++; } else { /* flush mode command */ ps_curr_inp->i4_buf_id = buf_id; /* set the input status to invalid flag */ ps_curr_inp->i4_inp_frm_data_valid_flag = 0; pi4_ctrl_ptr = (WORD32 *)ps_curr_inp->pv_synch_ctrl_bufs; *pi4_ctrl_ptr = IHEVCE_SYNCH_API_FLUSH_TAG; *(pi4_ctrl_ptr + 1) = 0; *(pi4_ctrl_ptr + 2) = IHEVCE_SYNCH_API_END_TAG; ps_curr_inp->i4_cmd_buf_size = 4 * 3; /* 4 bytes */ } /* ---------- set the buffer as produced ---------- */ ihevce_q_set_inp_data_buff_prod(ps_interface_ctxt, buf_id); ps_ctxt->u8_num_frames_encoded++; } else { /* Enable flush-mode and internal-flush once limit according to Eval-version is reached */ ps_ctxt->i4_flush_mode_on = 1; ps_ctxt->i4_internal_flush = 1; } } /* set encoder in flush mode if input buffer is NULL */ if(0 == ps_ctxt->i4_flush_mode_on) { if(NULL == ps_inp) { ps_ctxt->i4_flush_mode_on = 1; } } if((u4_latency < ps_ctxt->u8_num_frames_queued) || (1 == ps_ctxt->i4_flush_mode_on)) { /* --------------------------------------------------------------------- */ /* Output Processing */ /* --------------------------------------------------------------------- */ ihevce_receive_out_buffer(ps_ctxt, ps_out); } } else //Other bitrate and resolution instances { return IHEVCE_EFAIL; } return (IHEVCE_EOK); }