/****************************************************************************** * * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ /** ******************************************************************************* * @file * ih264e_svc_utils.c * * @brief * Contains utility functions used for SVC encoding * * @author * ittiam * * @par List of Functions: * - ih264e_svc_ref_list_refresh() * - ih264e_svc_inp_params_validate() * * @remarks * None * ******************************************************************************* */ #include #include #include "ih264_typedefs.h" /* Dependencies of ih264_buf_mgr.h */ /* Dependencies of ih264_list.h */ #include "ih264_error.h" #include "ih264_buf_mgr.h" #include "ih264_list.h" #include "ih264_trans_data.h" #include "ih264_size_defs.h" /* Dependencies of ih264_common_tables.h */ #include "ih264_defs.h" #include "ih264_structs.h" #include "ih264_common_tables.h" /* Dependencies of ih264e_bitstream.h */ #include "ih264e_error.h" /* Dependencies of ih264e_cabac_structs.h */ #include "ih264_cabac_tables.h" /* Dependencies of ime_structs.h */ #include "ime_defs.h" #include "ime_distortion_metrics.h" /* Dependencies of ih264e_structs.h */ #include "iv2.h" #include "ive2.h" #include "ih264_defs.h" #include "ih264_deblk_edge_filters.h" #include "ih264_inter_pred_filters.h" #include "ih264_structs.h" #include "ih264_trans_quant_itrans_iquant.h" #include "ih264e_bitstream.h" #include "ih264e_cabac_structs.h" #include "ime_statistics.h" #include "ime_structs.h" /* Dependencies of 'irc_picture_type.h' */ #include "irc_cntrl_param.h" #include "irc_frame_info_collector.h" #include "irc_mem_req_and_acq.h" /* Dependencies of 'irc_rate_control_api_structs' */ #include "irc_picture_type.h" #include "irc_rd_model.h" #include "irc_vbr_storage_vbv.h" #include "irc_est_sad.h" #include "irc_bit_allocation.h" #include "irc_mb_model_based.h" #include "irc_cbr_buffer_control.h" #include "irc_vbr_str_prms.h" #include "irc_common.h" #include "irc_rate_control_api_structs.h" #include "irc_rate_control_api.h" #include "irc_svc_rate_control_api.h" /* Dependencies of 'ih264e_utils.h' */ #include "ih264e_defs.h" #include "ih264e_structs.h" /* Dependencies of 'ih264e_utils.h' */ #include "irc_mem_req_and_acq.h" #include "ih264e_rc_mem_interface.h" #include "ih264e_time_stamp.h" #include "ih264e_utils.h" #include "ime.h" #include "isvc_macros.h" #include "isvce_cabac.h" #include "isvce_core_coding.h" #include "isvce_defs.h" #include "isvce_error.h" #include "isvce_me.h" #include "isvce_utils.h" #include "isvce_downscaler.h" #include "isvce_encode_header.h" #include "isvce_rate_control.h" #include "isvce_sub_pic_rc.h" static const UWORD32 gu4_downscaler_blk_size = 96; static FORCEINLINE UWORD32 isvce_get_downscaler_blk_dims(UWORD32 u4_frame_dim, UWORD32 u4_blk_pos, UWORD32 u4_default_blk_size) { return ((u4_frame_dim - u4_blk_pos * u4_default_blk_size) < u4_default_blk_size) ? (u4_frame_dim - u4_blk_pos * u4_default_blk_size) : u4_default_blk_size; } /** ******************************************************************************* * * @brief * Reference and MV bank Buffer Manager for SVC * * @par Description: * Here we will * 1) Find the correct ref pics for the current frame * 2) Free the ref pics that are not going to be used anymore * * 1) Finding correct ref pic * All pics needed for future are arranged in a picture list called * ps_codec->as_ref_set. Each picture in this will have a pic buffer and * MV buffer that is marked appropriately as BUF_MGR_REF, BUF_MGR_IO or * BUF_MGR_CODEC. pic_cnt, poc, and temporal_id will also be present. * The strategy is to pick the closest references that belongs to the * same temporal_id or lesser. The closeness is measured via the * smallest absolute difference between ref and cur pocs. * * Note that i4_pic_cnt == -1 is used to filter uninitialised ref pics. * Now since we only have max two ref pics, we will always find max 2 * ref pics. * * 2) Self explanatory * * @param[in] ps_codec * Pointer to codeec context * * @param[in] pps_ref_pics * Array of pointers to refPicBufs * * @param[in] pps_mv_bufs * Array of pointers to refMVBufs * * @param[in] e_pic_type * Picture type * * @returns Nothing * ******************************************************************************* */ static WORD32 isvce_ref_list_refresh(isvce_codec_t *ps_codec, svc_au_buf_t **pps_ref_pics, svc_au_data_t **pps_mv_bufs, WORD32 *pi4_ref_set_id, PIC_TYPE_T e_pic_type) { typedef struct { WORD32 i4_buf_id; WORD32 i4_abs_poc_diff; WORD8 i1_temporal_id; } ref_pic_props_t; ref_pic_props_t s_ref_pic_props = {0, 0, -1}; WORD32 i, buf_status; WORD32 i4_cur_pic_poc = ps_codec->i4_poc; WORD32 i4_cur_pic_temporal_id = isvce_svc_temporal_id_compute( ps_codec->i4_poc, ps_codec->s_cfg.s_svc_params.u1_num_temporal_layers, e_pic_type); if(e_pic_type == PIC_B) { return IH264E_FAIL; } ASSERT(1 == MAX_LAYER_REFERENCE_PICS); /* Pick a ref_pic for the current picture */ if(e_pic_type != PIC_IDR) { for(i = 0; i < ps_codec->i4_ref_buf_cnt; i++) { WORD32 i4_abs_poc_diff; WORD8 i1_temporal_id; if(ps_codec->as_ref_set[i].i4_pic_cnt == -1) { continue; } buf_status = ih264_buf_mgr_get_status(ps_codec->pv_ref_buf_mgr, ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id); if(buf_status & BUF_MGR_REF) { i4_abs_poc_diff = ABS(ps_codec->as_ref_set[i].i4_poc - i4_cur_pic_poc); i1_temporal_id = ps_codec->as_ref_set[i].ps_pic_buf->i1_temporal_id; if(s_ref_pic_props.i1_temporal_id > -1) { if((i1_temporal_id <= i4_cur_pic_temporal_id) && (s_ref_pic_props.i4_abs_poc_diff > i4_abs_poc_diff)) { s_ref_pic_props.i4_abs_poc_diff = i4_abs_poc_diff; s_ref_pic_props.i1_temporal_id = i1_temporal_id; s_ref_pic_props.i4_buf_id = i; } } else if(i1_temporal_id <= i4_cur_pic_temporal_id) { s_ref_pic_props.i4_abs_poc_diff = i4_abs_poc_diff; s_ref_pic_props.i1_temporal_id = i1_temporal_id; s_ref_pic_props.i4_buf_id = i; } } } if(s_ref_pic_props.i1_temporal_id < 0) { return IH264E_FAIL; } pps_ref_pics[0] = pps_ref_pics[1] = ps_codec->as_ref_set[s_ref_pic_props.i4_buf_id].ps_pic_buf; pps_mv_bufs[0] = pps_mv_bufs[1] = ps_codec->as_ref_set[s_ref_pic_props.i4_buf_id].ps_svc_au_data; /* Pick all ref pic_bufs to be freed. */ for(i = 0; i < ps_codec->i4_ref_buf_cnt; i++) { if(ps_codec->as_ref_set[i].i4_pic_cnt == -1) { continue; } buf_status = ih264_buf_mgr_get_status(ps_codec->pv_ref_buf_mgr, ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id); if((buf_status & (BUF_MGR_REF | BUF_MGR_CODEC | BUF_MGR_IO)) == 0) { ps_codec->as_ref_set[i].i4_pic_cnt = -1; ps_codec->as_ref_set[i].i4_poc = 32768; continue; } if(buf_status & BUF_MGR_REF) { if((i4_cur_pic_temporal_id <= ps_codec->as_ref_set[i].ps_pic_buf->i1_temporal_id) && (pps_ref_pics[0]->i4_frame_num != ps_codec->as_ref_set[i].ps_pic_buf->i4_frame_num) && (pps_ref_pics[0]->i4_frame_num != ps_codec->as_ref_set[i].ps_pic_buf->i4_frame_num)) { ih264_buf_mgr_release(ps_codec->pv_svc_au_data_store_mgr, ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id, BUF_MGR_REF); ih264_buf_mgr_release(ps_codec->pv_ref_buf_mgr, ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id, BUF_MGR_REF); } } } } else { for(i = 0; i < ps_codec->i4_ref_buf_cnt; i++) { if(ps_codec->as_ref_set[i].i4_pic_cnt == -1) { continue; } buf_status = ih264_buf_mgr_get_status(ps_codec->pv_ref_buf_mgr, ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id); if((buf_status & (BUF_MGR_REF | BUF_MGR_CODEC | BUF_MGR_IO)) == 0) { ps_codec->as_ref_set[i].i4_pic_cnt = -1; ps_codec->as_ref_set[i].i4_poc = 32768; continue; } if(buf_status & BUF_MGR_REF) { ih264_buf_mgr_release(ps_codec->pv_svc_au_data_store_mgr, ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id, BUF_MGR_REF); ih264_buf_mgr_release(ps_codec->pv_ref_buf_mgr, ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id, BUF_MGR_REF); } } } /* * Mark all reference pic with unused buffers to be free * We need this step since each one, ie ref, recon io etc only unset their * respective flags. Hence we need to combine togather and mark the ref set * accordingly */ pi4_ref_set_id[0] = -1; for(i = 0; i < ps_codec->i4_ref_buf_cnt; i++) { if(ps_codec->as_ref_set[i].i4_pic_cnt == -1) { pi4_ref_set_id[0] = i; continue; } buf_status = ih264_buf_mgr_get_status(ps_codec->pv_ref_buf_mgr, ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id); if((buf_status & (BUF_MGR_REF | BUF_MGR_CODEC | BUF_MGR_IO)) == 0) { ps_codec->as_ref_set[i].i4_pic_cnt = -1; ps_codec->as_ref_set[i].i4_poc = 32768; pi4_ref_set_id[0] = i; } } /* An asssert failure here means we donot have any free buffs */ if(pi4_ref_set_id[0] < 0) { return IH264E_FAIL; } return IH264E_SUCCESS; } /** ******************************************************************************* * * @brief * Validates SVC AU properties * * @param[in] ps_cfg * Cfg parameters * * @returns error code in conformance with 'IH264E_ERROR_T' * ******************************************************************************* */ WORD32 isvce_svc_au_props_validate(svc_inp_params_t *ps_svc_inp_params, UWORD32 u4_inp_wd, UWORD32 u4_inp_ht, UWORD32 u4_svc_comp_wd, UWORD32 u4_svc_comp_ht) { typedef struct { DOUBLE d_spatial_res_ratio; UWORD8 u1_max_num_spatial_layers; } spatial_layer_props_t; UWORD8 i; UWORD32 au4_svc_wd[MAX_NUM_SPATIAL_LAYERS]; UWORD32 au4_svc_ht[MAX_NUM_SPATIAL_LAYERS]; DOUBLE d_scaling_factor = ps_svc_inp_params->d_spatial_res_ratio; UWORD8 u1_num_spatial_layers = ps_svc_inp_params->u1_num_spatial_layers; const spatial_layer_props_t gas_valid_spatial_layer_props[] = {{1.5, 2}, {2, 3}}; UWORD32 u4_error_code = IV_SUCCESS; const UWORD8 u1_min_num_temporal_layers = 1; const UWORD8 u1_min_num_spatial_layers = 1; const UWORD8 u1_max_num_temporal_layers = MAX_NUM_TEMPORAL_LAYERS; const UWORD8 u1_max_num_spatial_layers = MAX_NUM_SPATIAL_LAYERS; const UWORD8 u1_num_valid_spatial_layer_props = sizeof(gas_valid_spatial_layer_props) / sizeof(gas_valid_spatial_layer_props[0]); if((ps_svc_inp_params->u1_num_temporal_layers < u1_min_num_temporal_layers) || (ps_svc_inp_params->u1_num_temporal_layers > u1_max_num_temporal_layers)) { u4_error_code |= IH264E_INVALID_SVC_PARAMS | IH264E_INVALID_NUM_TEMPORAL_LAYERS; } if((ps_svc_inp_params->u1_num_spatial_layers < u1_min_num_spatial_layers) || (ps_svc_inp_params->u1_num_spatial_layers > u1_max_num_spatial_layers)) { u4_error_code |= IH264E_INVALID_SVC_PARAMS | IH264E_INVALID_NUM_SPATIAL_LAYERS; } { UWORD8 u1_is_input_ratio_valid = 0; for(i = 0; i < u1_num_valid_spatial_layer_props; i++) { if(ps_svc_inp_params->d_spatial_res_ratio == gas_valid_spatial_layer_props[i].d_spatial_res_ratio) { u1_is_input_ratio_valid = 1; if(ps_svc_inp_params->u1_num_spatial_layers > gas_valid_spatial_layer_props[i].u1_max_num_spatial_layers) { u4_error_code |= IH264E_INVALID_SVC_PARAMS | IH264E_INVALID_NUM_SPATIAL_LAYERS; } break; } } if(!u1_is_input_ratio_valid) { u4_error_code |= IH264E_INVALID_SVC_PARAMS | IH264E_INVALID_SPATIAL_RES_RATIO; } } if((u4_svc_comp_wd > SVCE_MAX_INP_DIM) || (u4_svc_comp_ht > SVCE_MAX_INP_DIM) || ((u4_svc_comp_wd * u4_svc_comp_ht) > SVCE_MAX_INP_FRAME_SIZE) || (u4_svc_comp_wd % 16 != 0) || (u4_svc_comp_ht % 16 != 0)) { u4_error_code |= IH264E_INVALID_SVC_INPUT_DIMENSIONS; } /* Constraint from padding intrinsics */ if((u4_svc_comp_wd - u4_inp_wd) % 16) { u4_error_code |= IH264E_INVALID_SVC_INPUT_DIMENSIONS; } /* Constraint from 420p to 420sp conversion */ if((u4_svc_comp_ht - u4_inp_ht) % 4) { u4_error_code |= IH264E_INVALID_SVC_INPUT_DIMENSIONS; } au4_svc_wd[u1_num_spatial_layers - 1] = u4_svc_comp_wd; au4_svc_ht[u1_num_spatial_layers - 1] = u4_svc_comp_ht; for(i = (u1_num_spatial_layers - 1); i > 0; i--) { au4_svc_wd[i - 1] = au4_svc_wd[i] / d_scaling_factor; au4_svc_ht[i - 1] = au4_svc_ht[i] / d_scaling_factor; if((au4_svc_wd[i - 1] * d_scaling_factor != au4_svc_wd[i]) || (au4_svc_ht[i - 1] * d_scaling_factor != au4_svc_ht[i]) || (au4_svc_ht[i - 1] % 16 != 0) || (au4_svc_ht[i - 1] % 16 != 0)) { u4_error_code |= IH264E_INVALID_SVC_INPUT_DIMENSIONS; } } return u4_error_code; } /** ******************************************************************************* * * @brief * Validates SVC input params * * @param[in] ps_cfg * Cfg parameters * * @returns error code in conformance with 'IH264E_ERROR_T' * ******************************************************************************* */ WORD32 isvce_svc_inp_params_validate(isvce_init_ip_t *ps_ip, isvce_cfg_params_t *ps_cfg) { UWORD32 u4_error_code = isvce_svc_au_props_validate(&ps_ip->s_svc_inp_params, ps_ip->u4_wd, ps_ip->u4_ht, ps_cfg->u4_wd, ps_cfg->u4_ht); if(ps_cfg->u4_enable_alt_ref) { u4_error_code |= IH264E_INVALID_ALT_REF_OPTION; } if(ps_cfg->u4_num_bframes) { u4_error_code |= IH264E_BFRAMES_NOT_SUPPORTED; } if(ps_cfg->e_slice_mode != IVE_SLICE_MODE_NONE) { u4_error_code |= IH264E_SLICE_TYPE_INPUT_INVALID; } if(ps_cfg->e_content_type != IV_PROGRESSIVE) { u4_error_code |= IH264E_CONTENT_TYPE_NOT_SUPPORTED; } if(ps_cfg->u4_weighted_prediction) { u4_error_code |= IH264E_WEIGHTED_PRED_NOT_SUPPORTED; } return u4_error_code; } /** ******************************************************************************* * * @brief * Validates SVC RC params * * @param[in] ps_cfg * Cfg parameters * * @returns error code in conformance with 'IH264E_ERROR_T' * ******************************************************************************* */ static WORD32 isvce_svc_rc_params_validate(isvce_cfg_params_t *ps_cfg) { WORD32 i; /* RC requires total bits in a second to fit int32_t */ for(i = 0; i < ps_cfg->s_svc_params.u1_num_spatial_layers; i++) { if((((((UWORD64) ps_cfg->au4_target_bitrate[i]) * 1000llu) / ps_cfg->u4_tgt_frame_rate) * ps_cfg->u4_idr_frm_interval) > ((UWORD64) INT32_MAX)) { return IH264E_BITRATE_NOT_SUPPORTED; } } return IH264E_SUCCESS; } /** ******************************************************************************* * * @brief * Validates SVC frame-level input params * * @param[in] ps_cfg * Cfg parameters * * @returns error code in conformance with 'IH264E_ERROR_T' * ******************************************************************************* */ WORD32 isvce_svc_frame_params_validate( rate_control_api_t *aps_rate_control_api[MAX_NUM_SPATIAL_LAYERS], UWORD8 u1_num_spatial_layers) { WORD32 i; /* RC requires total bits in a second to fit int32_t */ for(i = 0; i < u1_num_spatial_layers; i++) { if((((UWORD64) irc_get_bits_per_frame(aps_rate_control_api[i])) * irc_get_intra_frame_interval(aps_rate_control_api[i])) > ((UWORD64) INT32_MAX)) { return IH264E_BITRATE_NOT_SUPPORTED; } } return IV_SUCCESS; } /** ******************************************************************************* * * @brief * Used to get reference picture buffer size for a given level and * and padding used * * @param[in] ps_svc_inp_params * Struct containing SVC specific input params * * @param[in] i4_pic_size * Number of luma samples (Width * Height) * * @param[in] i4_level * Level * * @param[in] i4_horz_pad * Total padding used in horizontal direction * * @param[in] i4_vert_pad * Total padding used in vertical direction * * @param[in] i4_num_ref_frames * Num Reference Frames * * @param[in] i4_num_reorder_frames * Num Reorder Frames * * @returns Total picture buffer size * ******************************************************************************* */ WORD32 isvce_get_total_svc_au_buf_size(svc_inp_params_t *ps_svc_inp_params, WORD32 i4_pic_size, WORD32 i4_level, WORD32 i4_horz_pad, WORD32 i4_vert_pad, WORD32 i4_num_ref_frames, WORD32 i4_num_reorder_frames) { WORD32 i; WORD32 size; WORD32 num_luma_samples; WORD32 lvl_idx; WORD32 max_wd, min_ht; WORD32 num_samples; WORD32 max_num_bufs; WORD32 pad = MAX(i4_horz_pad, i4_vert_pad); DOUBLE d_svc_size_multiplier = 1; for(i = 1; i < ps_svc_inp_params->u1_num_spatial_layers; i++) { d_svc_size_multiplier += 1. / pow(ps_svc_inp_params->d_spatial_res_ratio, i); } /* * If i4_num_ref_frames and num_reorder_frmaes is specified * Use minimum value */ max_num_bufs = (i4_num_ref_frames + i4_num_reorder_frames + MAX_CTXT_SETS + ps_svc_inp_params->u1_num_temporal_layers); /* Get i4_level index */ lvl_idx = ih264e_get_lvl_idx(i4_level); /* Maximum number of luma samples in a picture at given i4_level */ num_luma_samples = gai4_ih264_max_luma_pic_size[lvl_idx]; num_luma_samples = MAX(num_luma_samples, i4_pic_size); /* Account for chroma */ num_samples = num_luma_samples * 3 / 2; /* Maximum width of luma samples in a picture at given i4_level */ max_wd = gai4_ih264_max_wd_ht[lvl_idx]; /* Minimum height of luma samples in a picture at given i4_level */ min_ht = gai4_ih264_min_wd_ht[lvl_idx]; /* Allocation is required for * (Wd + i4_horz_pad) * (Ht + i4_vert_pad) * (2 * max_dpb_size + 1) * * Above expanded as * ((Wd * Ht) + (i4_horz_pad * i4_vert_pad) + Wd * i4_vert_pad + Ht * * i4_horz_pad) * (2 * max_dpb_size + 1) (Wd * Ht) * (2 * max_dpb_size + 1) + * ((i4_horz_pad * i4_vert_pad) + Wd * i4_vert_pad + Ht * i4_horz_pad) * (2 * * max_dpb_size + 1) Now max_dpb_size increases with smaller Wd and Ht, but Wd * * ht * max_dpb_size will still be lesser or equal to max_wd * max_ht * * dpb_size * * In the above equation (Wd * Ht) * (2 * max_dpb_size + 1) is accounted by * using num_samples * (2 * max_dpb_size + 1) below * * For the padded area use MAX(i4_horz_pad, i4_vert_pad) as pad * ((pad * pad) + pad * (Wd + Ht)) * (2 * max_dpb_size + 1) has to accounted * from the above for padding * * Since Width and Height can change worst Wd + Ht is when One of the * dimensions is max and other is min So use max_wd and min_ht */ /* Number of bytes in reference pictures */ size = num_samples * max_num_bufs; /* Account for Spatial Layers */ size = (WORD32) (size * d_svc_size_multiplier + 0.99); /* Account for padding area */ size += ((pad * pad) + pad * (max_wd + min_ht)) * 3 / 2 * max_num_bufs * ps_svc_inp_params->u1_num_spatial_layers; size += ps_svc_inp_params->u1_num_spatial_layers * sizeof(yuv_buf_props_t); return size; } /** ******************************************************************************* * * @brief * Used to get size of buffers used for storing prediction data * * @param[in] ps_svc_inp_params * Struct containing SVC specific input params * * @param[in] i4_num_luma_samples * Number of luma samples (Width * Height) * * @returns Size of buffers used for storing prediction data * ******************************************************************************* */ UWORD32 isvce_get_total_svc_au_data_size(WORD32 i4_num_luma_samples, UWORD8 u1_num_spatial_layers, DOUBLE d_spatial_res_ratio) { WORD32 i; UWORD32 u4_svc_au_data_size = 0; u4_svc_au_data_size += u1_num_spatial_layers * sizeof(svc_layer_data_t); for(i = 0; i < u1_num_spatial_layers; i++) { WORD32 i4_layer_luma_samples = ((DOUBLE) i4_num_luma_samples) / pow(pow(d_spatial_res_ratio, i), 2) + 0.99; WORD32 i4_num_mbs = i4_layer_luma_samples / (MB_SIZE * MB_SIZE); /* isvce_mb_info_t */ u4_svc_au_data_size += i4_num_mbs * sizeof(isvce_mb_info_t); /* pu4_num_pus_in_mb */ u4_svc_au_data_size += i4_num_mbs * sizeof(UWORD32); } return u4_svc_au_data_size; } /** ******************************************************************************* * * @brief Function to add buffers to SVC AU Data Store Manager * * @param[in] ps_codec * Pointer to codec context * * @returns error status * ******************************************************************************* */ IH264E_ERROR_T isvce_svc_au_data_mgr_add_bufs(isvce_codec_t *ps_codec) { IH264_ERROR_T ret; WORD32 i, j; UWORD8 *pu1_buf; svc_au_data_t *ps_svc_au_data = ps_codec->ps_svc_au_data_base; WORD32 i4_max_dpb_size = ps_codec->i4_ref_buf_cnt; WORD64 i8_alloc_mem_size = ps_codec->i4_svc_au_data_size; WORD32 i4_num_luma_samples = ALIGN16(ps_codec->s_cfg.u4_wd) * ALIGN16(ps_codec->s_cfg.u4_ht); UWORD8 u1_num_spatial_layers = ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers; DOUBLE d_spatial_res_ratio = ps_codec->s_cfg.s_svc_params.d_spatial_res_ratio; ps_codec->ps_svc_au_data = ps_svc_au_data; pu1_buf = (UWORD8 *) ps_svc_au_data; pu1_buf += BUF_MGR_MAX_CNT * sizeof(ps_svc_au_data[0]); i8_alloc_mem_size -= (BUF_MGR_MAX_CNT * sizeof(ps_svc_au_data[0])); i = 0; while(i < i4_max_dpb_size) { ps_svc_au_data->ps_svc_layer_data = (svc_layer_data_t *) pu1_buf; pu1_buf += u1_num_spatial_layers * sizeof(ps_svc_au_data->ps_svc_layer_data[0]); i8_alloc_mem_size -= u1_num_spatial_layers * sizeof(ps_svc_au_data->ps_svc_layer_data[0]); for(j = u1_num_spatial_layers - 1; j >= 0; j--) { WORD32 i4_layer_luma_samples = ((DOUBLE) i4_num_luma_samples) / pow(pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - j), 2) + 0.99; WORD32 i4_num_mbs = i4_layer_luma_samples / (MB_SIZE * MB_SIZE); ps_svc_au_data->ps_svc_layer_data[j].pu4_num_pus_in_mb = (UWORD32 *) pu1_buf; pu1_buf += i4_num_mbs * sizeof(ps_svc_au_data->ps_svc_layer_data[j].pu4_num_pus_in_mb[0]); i8_alloc_mem_size -= i4_num_mbs * sizeof(ps_svc_au_data->ps_svc_layer_data[j].pu4_num_pus_in_mb[0]); ps_svc_au_data->ps_svc_layer_data[j].ps_mb_info = (isvce_mb_info_t *) pu1_buf; pu1_buf += i4_num_mbs * sizeof(ps_svc_au_data->ps_svc_layer_data[j].ps_mb_info[0]); i8_alloc_mem_size -= i4_num_mbs * sizeof(ps_svc_au_data->ps_svc_layer_data[j].ps_mb_info[0]); ASSERT(i8_alloc_mem_size >= 0); } if(i8_alloc_mem_size < 0) { ps_codec->i4_error_code = IH264E_INSUFFICIENT_MEM_MVBANK; return IH264E_INSUFFICIENT_MEM_MVBANK; } ret = ih264_buf_mgr_add((buf_mgr_t *) ps_codec->pv_svc_au_data_store_mgr, ps_svc_au_data, i); if(IH264_SUCCESS != ret) { ps_codec->i4_error_code = IH264E_BUF_MGR_ERROR; return IH264E_BUF_MGR_ERROR; } ps_svc_au_data++; i++; } return IH264E_SUCCESS; } /** ******************************************************************************* * * @brief * Function to initialize svc_au_buf_t structs add au buffers to * buffer manager in case of non-shared mode * * @param[in] ps_codec * Pointer to codec context * * @returns error status * ******************************************************************************* */ IH264E_ERROR_T isvce_svc_au_buf_mgr_add_bufs(isvce_codec_t *ps_codec) { WORD32 i, j; WORD32 buf_ret; svc_au_buf_t *ps_pic_buf = ps_codec->ps_pic_buf; IH264E_ERROR_T ret = IH264E_SUCCESS; WORD32 i4_max_dpb_size = ps_codec->i4_ref_buf_cnt; WORD64 i8_alloc_mem_size = ps_codec->i4_total_pic_buf_size - BUF_MGR_MAX_CNT * sizeof(ps_pic_buf[0]); UWORD8 *pu1_buf = (UWORD8 *) ps_codec->ps_pic_buf; UWORD8 u1_num_spatial_layers = ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers; DOUBLE d_spatial_res_ratio = ps_codec->s_cfg.s_svc_params.d_spatial_res_ratio; pu1_buf += BUF_MGR_MAX_CNT * sizeof(svc_au_buf_t); for(i = 0; i < i4_max_dpb_size; i++) { WORD32 i4_total_fpel_mem_size = 0; ps_pic_buf->ps_layer_yuv_buf_props = (yuv_buf_props_t *) pu1_buf; pu1_buf += u1_num_spatial_layers * sizeof(ps_pic_buf->ps_layer_yuv_buf_props[0]); i8_alloc_mem_size -= u1_num_spatial_layers * sizeof(ps_pic_buf->ps_layer_yuv_buf_props[0]); if(i8_alloc_mem_size < 0) { ps_codec->i4_error_code = IH264E_INSUFFICIENT_MEM_PICBUF; return IH264E_INSUFFICIENT_MEM_PICBUF; } for(j = u1_num_spatial_layers - 1; j >= 0; j--) { WORD32 i4_layer_luma_wd = ((DOUBLE) ps_codec->s_cfg.u4_wd / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - j)) + 0.99; WORD32 i4_layer_luma_ht = ((DOUBLE) ps_codec->s_cfg.u4_ht / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - j)) + 0.99; WORD32 i4_layer_luma_samples = (ALIGN16(i4_layer_luma_wd) + PAD_WD) * (i4_layer_luma_ht + PAD_HT); WORD32 i4_layer_uv_wd = i4_layer_luma_wd; WORD32 i4_layer_uv_ht = i4_layer_luma_ht / 2.0 + 0.99; WORD32 i4_layer_uv_samples = (ALIGN16(i4_layer_uv_wd) + PAD_WD) * (i4_layer_uv_ht + PAD_HT); ps_pic_buf->ps_layer_yuv_buf_props[j].as_component_bufs[0].i4_data_stride = ALIGN16(i4_layer_luma_wd) + PAD_WD; ps_pic_buf->ps_layer_yuv_buf_props[j].as_component_bufs[0].pv_data = pu1_buf + ps_pic_buf->ps_layer_yuv_buf_props[j].as_component_bufs[0].i4_data_stride * PAD_TOP + PAD_LEFT; pu1_buf += i4_layer_luma_samples; ps_pic_buf->ps_layer_yuv_buf_props[j].as_component_bufs[1].i4_data_stride = ALIGN16(i4_layer_uv_wd) + PAD_WD; ps_pic_buf->ps_layer_yuv_buf_props[j].as_component_bufs[1].pv_data = pu1_buf + ps_pic_buf->ps_layer_yuv_buf_props[j].as_component_bufs[1].i4_data_stride * (PAD_TOP / 2) + PAD_LEFT; pu1_buf += i4_layer_uv_samples; ps_pic_buf->ps_layer_yuv_buf_props[j].u4_width = i4_layer_luma_wd; ps_pic_buf->ps_layer_yuv_buf_props[j].u4_height = i4_layer_luma_ht; ps_pic_buf->ps_layer_yuv_buf_props[j].u1_bit_depth = 8; ps_pic_buf->ps_layer_yuv_buf_props[j].e_color_format = IV_YUV_420SP_UV; i8_alloc_mem_size -= i4_layer_luma_samples + i4_layer_uv_samples; i4_total_fpel_mem_size += i4_layer_luma_samples + i4_layer_uv_samples; if(i8_alloc_mem_size < 0) { ps_codec->i4_error_code = IH264E_INSUFFICIENT_MEM_PICBUF; return IH264E_INSUFFICIENT_MEM_PICBUF; } } buf_ret = ih264_buf_mgr_add((buf_mgr_t *) ps_codec->pv_ref_buf_mgr, ps_pic_buf, i); if(0 != buf_ret) { ps_codec->i4_error_code = IH264E_BUF_MGR_ERROR; return IH264E_BUF_MGR_ERROR; } pu1_buf += (HPEL_PLANES_CNT - 1) * i4_total_fpel_mem_size; ps_pic_buf++; } return ret; } /** ******************************************************************************* * * @brief * Returns size of buffers for storing SVC input data * * @param[in] u1_num_spatial_layers * Num Spatial Layers * * @param[in] d_spatial_res_ratio * Resolution Ratio b/w spatial layers * * @param[in] u4_wd * Input Width * * @param[in] u4_ht * Input Height * * @returns Size of buffers * ******************************************************************************* */ UWORD32 isvce_get_svc_inp_buf_size(UWORD8 u1_num_spatial_layers, DOUBLE d_spatial_res_ratio, UWORD32 u4_wd, UWORD32 u4_ht) { padding_dims_t s_pad_dims; UWORD32 i; UWORD8 u1_filter_padding_size_x, u1_filter_padding_size_y; UWORD32 u4_size = 0; isvce_get_downscaler_padding_dims(&s_pad_dims); u1_filter_padding_size_x = s_pad_dims.u1_left_pad_size + s_pad_dims.u1_right_pad_size; u1_filter_padding_size_y = s_pad_dims.u1_top_pad_size + s_pad_dims.u1_bottom_pad_size; for(i = 0; i < u1_num_spatial_layers; i++) { WORD32 i4_layer_luma_wd = ((DOUBLE) u4_wd / pow(d_spatial_res_ratio, i)) + 0.99; WORD32 i4_layer_luma_ht = ((DOUBLE) u4_ht / pow(d_spatial_res_ratio, i)) + 0.99; WORD32 i4_layer_luma_samples = (ALIGN16(i4_layer_luma_wd) + PAD_WD + u1_filter_padding_size_x) * (i4_layer_luma_ht + PAD_HT + u1_filter_padding_size_y); WORD32 i4_layer_uv_wd = i4_layer_luma_wd; WORD32 i4_layer_uv_ht = i4_layer_luma_ht / 2.0 + 0.99; /* u1_filter_padding_size_x * 2 because U and V both need same amount of padding */ WORD32 i4_layer_uv_samples = (ALIGN16(i4_layer_uv_wd) + PAD_WD + u1_filter_padding_size_x * 2) * (i4_layer_uv_ht + PAD_HT + u1_filter_padding_size_y); u4_size += (i4_layer_luma_samples + i4_layer_uv_samples) * sizeof(UWORD8); } return SVC_MAX_NUM_INP_FRAMES * u4_size; } /** ******************************************************************************* * * @brief * Function to initialize svc input buffers * * @param[in] ps_codec * Pointer to codec context * * @param[in] ps_mem_rec * Pointer to memory allocated for input buffers * ******************************************************************************* */ void isvce_svc_inp_buf_init(isvce_codec_t *ps_codec, iv_mem_rec_t *ps_mem_rec) { padding_dims_t s_pad_dims; WORD32 i, j; UWORD8 u1_filter_padding_size_x, u1_filter_padding_size_y; DOUBLE d_spatial_res_ratio = ps_codec->s_cfg.s_svc_params.d_spatial_res_ratio; UWORD8 u1_num_spatial_layers = ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers; UWORD32 u4_wd = ps_codec->s_cfg.u4_wd; UWORD32 u4_ht = ps_codec->s_cfg.u4_ht; UWORD8 *pu1_buf = ps_mem_rec->pv_base; WORD64 i8_alloc_mem_size = isvce_get_svc_inp_buf_size(u1_num_spatial_layers, d_spatial_res_ratio, u4_wd, u4_ht); isvce_get_downscaler_padding_dims(&s_pad_dims); u1_filter_padding_size_x = s_pad_dims.u1_left_pad_size + s_pad_dims.u1_right_pad_size; u1_filter_padding_size_y = s_pad_dims.u1_top_pad_size + s_pad_dims.u1_bottom_pad_size; for(i = 0; i < SVC_MAX_NUM_INP_FRAMES; i++) { ps_codec->as_inp_list[i].s_svc_params = ps_codec->s_cfg.s_svc_params; for(j = u1_num_spatial_layers - 1; j >= 0; j--) { WORD32 i4_layer_luma_wd = ((DOUBLE) u4_wd / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - j)) + 0.99; WORD32 i4_layer_luma_ht = ((DOUBLE) u4_ht / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - j)) + 0.99; WORD32 i4_layer_luma_samples = (ALIGN16(i4_layer_luma_wd) + PAD_WD + u1_filter_padding_size_x) * (i4_layer_luma_ht + PAD_HT + u1_filter_padding_size_y); WORD32 i4_layer_uv_wd = i4_layer_luma_wd; WORD32 i4_layer_uv_ht = i4_layer_luma_ht / 2.0 + 0.99; /* u1_filter_padding_size_x * 2 because U and V both need same amount of padding */ WORD32 i4_layer_uv_samples = (ALIGN16(i4_layer_uv_wd) + PAD_WD + u1_filter_padding_size_x * 2) * (i4_layer_uv_ht + PAD_HT + u1_filter_padding_size_y); ps_codec->as_inp_list[i].as_layer_yuv_buf_props[j].as_component_bufs[Y].i4_data_stride = ALIGN16(i4_layer_luma_wd) + PAD_WD + u1_filter_padding_size_x; ps_codec->as_inp_list[i].as_layer_yuv_buf_props[j].as_component_bufs[Y].pv_data = pu1_buf + ps_codec->as_inp_list[i] .as_layer_yuv_buf_props[j] .as_component_bufs[Y] .i4_data_stride * (PAD_TOP + s_pad_dims.u1_top_pad_size) + (PAD_LEFT + s_pad_dims.u1_left_pad_size); pu1_buf += i4_layer_luma_samples * sizeof(UWORD8); i8_alloc_mem_size -= i4_layer_luma_samples * sizeof(UWORD8); ps_codec->as_inp_list[i] .as_layer_yuv_buf_props[j] .as_component_bufs[UV] .i4_data_stride = ALIGN16(i4_layer_uv_wd) + PAD_WD + u1_filter_padding_size_x * 2; ps_codec->as_inp_list[i].as_layer_yuv_buf_props[j].as_component_bufs[UV].pv_data = pu1_buf + ps_codec->as_inp_list[i] .as_layer_yuv_buf_props[j] .as_component_bufs[UV] .i4_data_stride * (PAD_TOP + s_pad_dims.u1_top_pad_size) + (PAD_LEFT + s_pad_dims.u1_left_pad_size * 2); pu1_buf += i4_layer_uv_samples * sizeof(UWORD8); i8_alloc_mem_size -= i4_layer_uv_samples * sizeof(UWORD8); /* Chroma is always stored interleaved */ ps_codec->as_inp_list[i].as_layer_yuv_buf_props[j].as_component_bufs[V].pv_data = NULL; ps_codec->as_inp_list[i].as_layer_yuv_buf_props[j].u1_bit_depth = 8; ps_codec->as_inp_list[i].as_layer_yuv_buf_props[j].e_color_format = IV_YUV_420SP_UV; ps_codec->as_inp_list[i].as_layer_yuv_buf_props[j].u4_width = i4_layer_luma_wd; ps_codec->as_inp_list[i].as_layer_yuv_buf_props[j].u4_height = i4_layer_luma_ht; ASSERT(i8_alloc_mem_size >= 0); } } } void isvce_init_svc_dimension(isvce_inp_buf_t *ps_inp) { WORD32 i; UWORD8 u1_num_spatial_layers = ps_inp->s_svc_params.u1_num_spatial_layers; DOUBLE d_spatial_res_ratio = ps_inp->s_svc_params.d_spatial_res_ratio; UWORD32 u4_wd = ps_inp->s_inp_props.s_raw_buf.au4_wd[Y]; UWORD32 u4_ht = ps_inp->s_inp_props.s_raw_buf.au4_ht[Y]; for(i = 0; i < u1_num_spatial_layers; i++) { ps_inp->as_layer_yuv_buf_props[i].u4_width = ((DOUBLE) u4_wd / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; ps_inp->as_layer_yuv_buf_props[i].u4_height = ((DOUBLE) u4_ht / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; } } /** ******************************************************************************* * * @brief * Pads input buf as assumed by the downscaler filter * * @param[in] ps_codec * Pointer to codec ctxt * * @param[in] ps_inp * Pointer to svc input buffer * * @param[in] u1_svc_layer_index * SVC layer index of the buffer * ******************************************************************************* */ static void isvce_pad_buf_for_filtering(isvce_codec_t *ps_codec, isvce_inp_buf_t *ps_inp, UWORD8 u1_svc_layer_index) { padding_dims_t s_pad_dims; UWORD8 *pu1_buf; UWORD32 u4_buf_width, u4_buf_height; UWORD8 u1_pad_left_size; UWORD8 u1_pad_right_size; UWORD8 u1_pad_top_size; UWORD8 u1_pad_bottom_size; UWORD8 u1_filter_padding_size_x; UWORD8 u1_filter_padding_size_chroma_x; ASSERT(ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].e_color_format == IV_YUV_420SP_UV); isvce_get_downscaler_padding_dims(&s_pad_dims); u1_pad_left_size = s_pad_dims.u1_left_pad_size; u1_pad_right_size = s_pad_dims.u1_right_pad_size; u1_pad_top_size = s_pad_dims.u1_top_pad_size; u1_pad_bottom_size = s_pad_dims.u1_bottom_pad_size; u1_filter_padding_size_x = u1_pad_left_size + u1_pad_right_size; u1_filter_padding_size_chroma_x = u1_filter_padding_size_x * 2; u4_buf_width = ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].u4_width; u4_buf_height = ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].u4_height; pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index] .as_component_bufs[0] .pv_data); ps_codec->pf_pad_left_luma( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[0].i4_data_stride, u4_buf_height, u1_pad_left_size); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index] .as_component_bufs[0] .pv_data); pu1_buf += u4_buf_width; ps_codec->pf_pad_right_luma( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[0].i4_data_stride, u4_buf_height, u1_pad_right_size); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index] .as_component_bufs[1] .pv_data); ps_codec->pf_pad_left_chroma( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[1].i4_data_stride, u4_buf_height / 2, u1_pad_left_size * 2); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index] .as_component_bufs[1] .pv_data); pu1_buf += u4_buf_width; ps_codec->pf_pad_right_chroma( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[1].i4_data_stride, u4_buf_height / 2, u1_pad_right_size * 2); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index] .as_component_bufs[0] .pv_data) - u1_pad_left_size; ps_codec->pf_pad_top( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[0].i4_data_stride, (u4_buf_width + u1_filter_padding_size_x), u1_pad_top_size); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index] .as_component_bufs[0] .pv_data) - u1_pad_left_size; pu1_buf += (u4_buf_height * ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[0].i4_data_stride); ps_codec->pf_pad_bottom( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[0].i4_data_stride, (u4_buf_width + u1_filter_padding_size_x), u1_pad_bottom_size); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index] .as_component_bufs[1] .pv_data) - u1_pad_left_size * 2; ps_codec->pf_pad_top( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[1].i4_data_stride, (u4_buf_width + u1_filter_padding_size_chroma_x), u1_pad_top_size); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index] .as_component_bufs[1] .pv_data) - u1_pad_left_size * 2; pu1_buf += ((u4_buf_height / 2) * ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[1].i4_data_stride); ps_codec->pf_pad_bottom( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_svc_layer_index].as_component_bufs[1].i4_data_stride, (u4_buf_width + u1_filter_padding_size_chroma_x), u1_pad_bottom_size); } /** ******************************************************************************* * * @brief * Pads raw input to satisfy SVC compliant input dimensions * * @param[in] ps_codec * Pointer to codec ctxt * * @param[in] ps_inp * Pointer to svc input buffer * ******************************************************************************* */ static void isvce_pad_input_to_svc_compliant_dims(isvce_codec_t *ps_codec, isvce_inp_buf_t *ps_inp) { UWORD8 *pu1_buf; UWORD32 u4_raw_input_wd, u4_raw_input_ht, u4_padded_width, u4_padded_height, u4_width_delta, u4_height_delta; UWORD8 u1_num_layers = ps_inp->s_svc_params.u1_num_spatial_layers; ASSERT(ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].e_color_format == IV_YUV_420SP_UV); u4_padded_width = ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].u4_width; u4_padded_height = ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].u4_height; u4_raw_input_wd = ps_inp->s_inp_props.s_raw_buf.au4_wd[0]; u4_raw_input_ht = ps_inp->s_inp_props.s_raw_buf.au4_ht[0]; u4_width_delta = u4_padded_width - u4_raw_input_wd; u4_height_delta = u4_padded_height - u4_raw_input_ht; ASSERT(!(u4_width_delta & 1)); ASSERT(!(u4_height_delta & 1)); if(u4_width_delta) { pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[0] .pv_data); pu1_buf += ((u4_width_delta / 2) + (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[0] .i4_data_stride) * (u4_height_delta / 2)); ps_codec->pf_pad_left_luma( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[0].i4_data_stride, u4_padded_height, u4_width_delta / 2); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[0] .pv_data); pu1_buf += ((u4_width_delta / 2) + (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[0] .i4_data_stride) * (u4_height_delta / 2)); pu1_buf += u4_raw_input_wd; ps_codec->pf_pad_right_luma( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[0].i4_data_stride, u4_padded_height, u4_width_delta / 2); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[1] .pv_data); pu1_buf += ((u4_width_delta / 2) + (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[1] .i4_data_stride) * (u4_height_delta / 4)); ps_codec->pf_pad_left_chroma( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[1].i4_data_stride, u4_padded_height / 2, u4_width_delta / 2); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[1] .pv_data); pu1_buf += ((u4_width_delta / 2) + (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[1] .i4_data_stride) * (u4_height_delta / 4)); pu1_buf += u4_raw_input_wd; ps_codec->pf_pad_right_chroma( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[1].i4_data_stride, u4_padded_height / 2, u4_width_delta / 2); } if(u4_height_delta) { pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[0] .pv_data); pu1_buf += ((ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[0] .i4_data_stride) * (u4_height_delta / 2)); ps_codec->pf_pad_top( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[0].i4_data_stride, u4_padded_width, u4_height_delta / 2); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[0] .pv_data); pu1_buf += ((ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[0] .i4_data_stride) * (u4_height_delta / 2)); pu1_buf += (u4_raw_input_ht * ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[0].i4_data_stride); ps_codec->pf_pad_bottom( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[0].i4_data_stride, u4_padded_width, u4_height_delta / 2); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[1] .pv_data); pu1_buf += ((ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[1] .i4_data_stride) * (u4_height_delta / 4)); ps_codec->pf_pad_top( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[1].i4_data_stride, u4_padded_width, u4_height_delta / 4); pu1_buf = (UWORD8 *) (ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[1] .pv_data); pu1_buf += ((ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1] .as_component_bufs[1] .i4_data_stride) * (u4_height_delta / 4)); pu1_buf += ((u4_raw_input_ht / 2) * ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[1].i4_data_stride); ps_codec->pf_pad_bottom( pu1_buf, ps_inp->as_layer_yuv_buf_props[u1_num_layers - 1].as_component_bufs[1].i4_data_stride, u4_padded_width, u4_height_delta / 4); } } /** ******************************************************************************* * * @brief * Format conversion and downsampling for deriving spatial layer inputs * * @param[in] ps_inp * Pointer to input buffer * ******************************************************************************* */ void isvce_svc_inp_buf_populate(isvce_codec_t *ps_codec, isvce_inp_buf_t *ps_inp) { yuv_buf_props_t s_src_buf_props, s_dst_buf_props; UWORD32 i; UWORD32 u4_blk_x, u4_blk_y; UWORD8 *pu1_planar_y, *pu1_planar_u, *pu1_planar_v, *pu1_semi_planar_y, *pu1_semi_planar_uv; UWORD8 *pu1_src_luma, *pu1_src_chroma, *pu1_dst_luma, *pu1_dst_chroma; UWORD32 u4_num_blocks_x, u4_num_blocks_y; UWORD32 u4_scaled_block_wd, u4_scaled_block_ht; UWORD32 u4_blk_wd_luma, u4_blk_ht_luma; downscaler_ctxt_t *ps_scaler = &ps_codec->s_scaler; isa_dependent_fxns_t *ps_isa_dependent_fxns = &ps_codec->s_isa_dependent_fxns; mem_fxns_t *ps_mem_fxns = &ps_isa_dependent_fxns->s_mem_fxns; const UWORD8 u1_num_yuv_components_420sp = NUM_SP_COMPONENTS; UWORD8 u1_num_spatial_layers = ps_inp->s_svc_params.u1_num_spatial_layers; UWORD32 u4_padded_width = ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1].u4_width; UWORD32 u4_padded_height = ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1].u4_height; UWORD32 u4_raw_input_wd = ps_inp->s_inp_props.s_raw_buf.au4_wd[0]; UWORD32 u4_raw_input_ht = ps_inp->s_inp_props.s_raw_buf.au4_ht[0]; UWORD32 u4_width_delta = u4_padded_width - u4_raw_input_wd; UWORD32 u4_height_delta = u4_padded_height - u4_raw_input_ht; ASSERT(!(u4_width_delta & 1)); ASSERT(!(u4_height_delta & 1)); ASSERT((ps_inp->s_inp_props.s_raw_buf.e_color_fmt == IV_YUV_420P) || (ps_inp->s_inp_props.s_raw_buf.e_color_fmt == IV_YUV_420SP_UV)); /* Check is input is valid */ if(!(ps_inp->s_inp_props.s_raw_buf.apv_bufs[0])) { ASSERT(0); return; } /* Convert the input into semi-planar in case of other formats */ if(ps_inp->s_inp_props.s_raw_buf.e_color_fmt == IV_YUV_420P) { pu1_planar_y = (UWORD8 *) ps_inp->s_inp_props.s_raw_buf.apv_bufs[0]; pu1_planar_u = (UWORD8 *) ps_inp->s_inp_props.s_raw_buf.apv_bufs[1]; pu1_planar_v = (UWORD8 *) ps_inp->s_inp_props.s_raw_buf.apv_bufs[2]; pu1_semi_planar_y = (UWORD8 *) ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1] .as_component_bufs[0] .pv_data; pu1_semi_planar_uv = (UWORD8 *) ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1] .as_component_bufs[1] .pv_data; pu1_semi_planar_y += ((u4_width_delta / 2) + (ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1] .as_component_bufs[0] .i4_data_stride) * (u4_height_delta / 2)); pu1_semi_planar_uv += ((u4_width_delta / 2) + (ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1] .as_component_bufs[1] .i4_data_stride) * (u4_height_delta / 4)); ps_codec->pf_ih264e_conv_420p_to_420sp( pu1_planar_y, pu1_planar_u, pu1_planar_v, pu1_semi_planar_y, pu1_semi_planar_uv, ps_inp->s_inp_props.s_raw_buf.au4_ht[0], ps_inp->s_inp_props.s_raw_buf.au4_wd[0], ps_inp->s_inp_props.s_raw_buf.au4_strd[0], ps_inp->s_inp_props.s_raw_buf.au4_strd[1], ps_inp->s_inp_props.s_raw_buf.au4_strd[2], ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1] .as_component_bufs[0] .i4_data_stride, ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1] .as_component_bufs[1] .i4_data_stride, 0); } else { UWORD32 u4_wd, u4_ht; UWORD8 u1_comp; UWORD32 au4_arr_dims[4]; UWORD8 *pu1_src, *pu1_dst; au4_arr_dims[0] = ps_inp->s_inp_props.s_raw_buf.au4_wd[0]; au4_arr_dims[1] = ps_inp->s_inp_props.s_raw_buf.au4_ht[0]; au4_arr_dims[2] = ps_inp->s_inp_props.s_raw_buf.au4_wd[1]; au4_arr_dims[3] = ps_inp->s_inp_props.s_raw_buf.au4_ht[1]; for(u1_comp = 0; u1_comp < u1_num_yuv_components_420sp; u1_comp++) { u4_wd = au4_arr_dims[u1_comp * 2]; u4_ht = au4_arr_dims[(u1_comp * 2) + 1]; pu1_dst = (UWORD8 *) ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1] .as_component_bufs[u1_comp] .pv_data; pu1_dst += ((u4_width_delta / 2) + (ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1] .as_component_bufs[u1_comp] .i4_data_stride) * ((u4_height_delta / 2) / (u1_comp + 1))); pu1_src = ps_inp->s_inp_props.s_raw_buf.apv_bufs[u1_comp]; ps_mem_fxns->pf_copy_2d(pu1_dst, ps_inp->as_layer_yuv_buf_props[u1_num_spatial_layers - 1] .as_component_bufs[u1_comp] .i4_data_stride, pu1_src, ps_inp->s_inp_props.s_raw_buf.au4_strd[u1_comp], u4_wd, u4_ht); } } /* Padding input to satisfy SVC constraints */ isvce_pad_input_to_svc_compliant_dims(ps_codec, ps_inp); /* Downscaling */ for(i = u1_num_spatial_layers - 1; i > 0; i--) { const UWORD32 u4_default_scaled_blk_wd = gu4_downscaler_blk_size / ps_codec->s_cfg.s_svc_params.d_spatial_res_ratio + 0.5; const UWORD32 u4_default_scaled_blk_ht = gu4_downscaler_blk_size / ps_codec->s_cfg.s_svc_params.d_spatial_res_ratio + 0.5; isvce_pad_buf_for_filtering(ps_codec, ps_inp, i); s_src_buf_props = ps_inp->as_layer_yuv_buf_props[i]; s_dst_buf_props = ps_inp->as_layer_yuv_buf_props[i - 1]; u4_num_blocks_x = (s_src_buf_props.u4_width + (gu4_downscaler_blk_size - 1)) / gu4_downscaler_blk_size; u4_num_blocks_y = (s_src_buf_props.u4_height + (gu4_downscaler_blk_size - 1)) / gu4_downscaler_blk_size; pu1_src_luma = (UWORD8 *) s_src_buf_props.as_component_bufs[Y].pv_data; pu1_src_chroma = (UWORD8 *) s_src_buf_props.as_component_bufs[U].pv_data; pu1_dst_luma = (UWORD8 *) s_dst_buf_props.as_component_bufs[Y].pv_data; pu1_dst_chroma = (UWORD8 *) s_dst_buf_props.as_component_bufs[U].pv_data; for(u4_blk_x = 0; u4_blk_x < u4_num_blocks_x; u4_blk_x++) { for(u4_blk_y = 0; u4_blk_y < u4_num_blocks_y; u4_blk_y++) { u4_blk_wd_luma = isvce_get_downscaler_blk_dims(s_src_buf_props.u4_width, u4_blk_x, gu4_downscaler_blk_size); u4_blk_ht_luma = isvce_get_downscaler_blk_dims(s_src_buf_props.u4_height, u4_blk_y, gu4_downscaler_blk_size); u4_scaled_block_wd = isvce_get_downscaler_blk_dims( s_dst_buf_props.u4_width, u4_blk_x, u4_default_scaled_blk_wd); u4_scaled_block_ht = isvce_get_downscaler_blk_dims( s_dst_buf_props.u4_height, u4_blk_y, u4_default_scaled_blk_ht); s_src_buf_props.as_component_bufs[Y].pv_data = pu1_src_luma + (u4_blk_x * gu4_downscaler_blk_size + u4_blk_y * gu4_downscaler_blk_size * s_src_buf_props.as_component_bufs[Y].i4_data_stride); s_src_buf_props.as_component_bufs[U].pv_data = pu1_src_chroma + (u4_blk_x * gu4_downscaler_blk_size + u4_blk_y * (gu4_downscaler_blk_size / 2) * s_src_buf_props.as_component_bufs[U].i4_data_stride); s_dst_buf_props.as_component_bufs[Y].pv_data = pu1_dst_luma + (u4_blk_x * u4_default_scaled_blk_wd + u4_blk_y * u4_default_scaled_blk_ht * s_dst_buf_props.as_component_bufs[Y].i4_data_stride); s_dst_buf_props.as_component_bufs[U].pv_data = pu1_dst_chroma + (u4_blk_x * u4_default_scaled_blk_wd + u4_blk_y * (u4_default_scaled_blk_ht / 2) * s_dst_buf_props.as_component_bufs[U].i4_data_stride); ASSERT(!(u4_scaled_block_wd & 1)); ASSERT(!(u4_scaled_block_ht & 1)); isvce_process_downscaler(ps_scaler, &s_src_buf_props, &s_dst_buf_props, u4_blk_wd_luma, u4_blk_ht_luma); } } } UNUSED(u4_scaled_block_wd); UNUSED(u4_scaled_block_ht); } /** ******************************************************************************* * * @brief * calculates the greatest common divisor between the two parameters. * ******************************************************************************* */ static DOUBLE isvce_get_GCD(DOUBLE a, DOUBLE b) { if(b == 0) { return a; } return isvce_get_GCD(b, fmod(a, b)); } /** ******************************************************************************* * * @brief * calculates the least common multiple between the two parameters * ******************************************************************************* */ static DOUBLE isvce_get_LCM(DOUBLE a, DOUBLE b) { return (a / isvce_get_GCD(a, b)) * b; } /** ******************************************************************************* * * @brief * sets the width and height in config structure to SVC compliant width and * height * * @param[in] ps_cfg * Pointer to config struct * * @param[in] u4_app_wd * width of the YUV as read by the app * * @param[in] u4_app_ht * height of the YUV as read by the app * ******************************************************************************* */ void isvce_get_svc_compliant_dimensions(UWORD8 u1_num_spatial_layers, DOUBLE d_scaling_factor, UWORD32 u4_wd, UWORD32 u4_ht, UWORD32 *pu4_svc_comp_wd, UWORD32 *pu4_svc_comp_ht) { DOUBLE d_scaling_factor_power_num_layers_minus1 = 0; UWORD32 u4_constraint_offset = 0; d_scaling_factor_power_num_layers_minus1 = pow(d_scaling_factor, u1_num_spatial_layers - 1); if(fmod(16, d_scaling_factor_power_num_layers_minus1)) { u4_constraint_offset = (UWORD32) isvce_get_LCM(16, d_scaling_factor_power_num_layers_minus1); } else { u4_constraint_offset = (UWORD32) (16 * d_scaling_factor_power_num_layers_minus1); } if(u4_wd % u4_constraint_offset) { *pu4_svc_comp_wd = u4_wd - ((u4_wd) % u4_constraint_offset) + u4_constraint_offset; } else { *pu4_svc_comp_wd = u4_wd; } if(u4_ht % u4_constraint_offset) { *pu4_svc_comp_ht = u4_ht - ((u4_ht) % u4_constraint_offset) + u4_constraint_offset; } else { *pu4_svc_comp_ht = u4_ht; } } /** ******************************************************************************* * * @brief * Returns size of buffers for storing SVC layer nbr info * * @param[in] u1_num_spatial_layers * Num Spatial Layers * * @param[in] d_spatial_res_ratio * Resolution Ratio b/w spatial layers * * @param[in] u4_wd * Input Width * * @returns Size of buffers * ******************************************************************************* */ UWORD32 isvce_get_svc_nbr_info_buf_size(UWORD8 u1_num_spatial_layers, DOUBLE d_spatial_res_ratio, UWORD32 u4_wd, UWORD32 u4_ht) { UWORD32 i; UWORD32 u4_size = 0; ASSERT(1 == MAX_CTXT_SETS); u4_size += MAX_PROCESS_CTXT * u1_num_spatial_layers * sizeof(nbr_info_t); for(i = 0; i < u1_num_spatial_layers; i++) { WORD32 i4_layer_luma_wd = ((DOUBLE) u4_wd / pow(d_spatial_res_ratio, i)) + 0.99; WORD32 i4_layer_luma_ht = ((DOUBLE) u4_ht / pow(d_spatial_res_ratio, i)) + 0.99; WORD32 i4_num_mbs_in_row = i4_layer_luma_wd / MB_SIZE; WORD32 i4_num_mbs_in_col = i4_layer_luma_ht / MB_SIZE; /* ps_top_row_mb_info */ u4_size += (i4_num_mbs_in_row + 1) * i4_num_mbs_in_col * sizeof(isvce_mb_info_t); /* ps_left_mb_info */ u4_size += MAX_PROCESS_CTXT * sizeof(isvce_mb_info_t); /* ps_top_mb_intra_modes */ u4_size += (i4_num_mbs_in_row + 1) * i4_num_mbs_in_col * sizeof(mb_intra_modes_t); /* ps_left_mb_intra_modes */ u4_size += MAX_PROCESS_CTXT * sizeof(mb_intra_modes_t); } return u4_size; } /** ******************************************************************************* * * @brief * Function to initialize svc nbr info buffers * * @param[in] ps_codec * Pointer to codec context * * @param[in] ps_mem_rec * Pointer to memory allocated for input buffers * ******************************************************************************* */ void isvce_svc_nbr_info_buf_init(isvce_codec_t *ps_codec, iv_mem_rec_t *ps_mem_rec) { WORD32 i, j; DOUBLE d_spatial_res_ratio = ps_codec->s_cfg.s_svc_params.d_spatial_res_ratio; UWORD8 u1_num_spatial_layers = ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers; UWORD32 u4_wd = ps_codec->s_cfg.u4_wd; UWORD32 u4_ht = ps_codec->s_cfg.u4_ht; UWORD8 *pu1_buf = ps_mem_rec->pv_base; WORD64 i8_alloc_mem_size = isvce_get_svc_nbr_info_buf_size(u1_num_spatial_layers, d_spatial_res_ratio, u4_wd, u4_ht); ASSERT(1 == MAX_CTXT_SETS); for(i = 0; i < MAX_PROCESS_CTXT; i++) { ps_codec->as_process[i].s_nbr_info_base.ps_layer_nbr_info = (nbr_info_t *) pu1_buf; pu1_buf += u1_num_spatial_layers * sizeof(ps_codec->as_process[i].s_nbr_info_base.ps_layer_nbr_info[0]); i8_alloc_mem_size -= u1_num_spatial_layers * sizeof(ps_codec->as_process[i].s_nbr_info_base.ps_layer_nbr_info[0]); for(j = u1_num_spatial_layers - 1; j >= 0; j--) { ps_codec->as_process[i].s_nbr_info_base.ps_layer_nbr_info[j].ps_left_mb_info = (isvce_mb_info_t *) pu1_buf; ps_codec->as_process[i].s_nbr_info.ps_left_mb_info = (isvce_mb_info_t *) pu1_buf; pu1_buf += sizeof(ps_codec->as_process[i].s_nbr_info.ps_left_mb_info[0]); i8_alloc_mem_size -= sizeof(ps_codec->as_process[i].s_nbr_info.ps_left_mb_info[0]); ps_codec->as_process[i].s_nbr_info_base.ps_layer_nbr_info[j].ps_left_mb_intra_modes = (mb_intra_modes_t *) pu1_buf; ps_codec->as_process[i].s_nbr_info.ps_left_mb_intra_modes = (mb_intra_modes_t *) pu1_buf; pu1_buf += sizeof(ps_codec->as_process[i].s_nbr_info.ps_left_mb_intra_modes[0]); i8_alloc_mem_size -= sizeof(ps_codec->as_process[i].s_nbr_info.ps_left_mb_intra_modes[0]); } ASSERT(i8_alloc_mem_size >= 0); } for(i = u1_num_spatial_layers - 1; i >= 0; i--) { isvce_mb_info_t *ps_top_mb_info; mb_intra_modes_t *ps_top_intra_modes; WORD32 i4_layer_luma_wd = ((DOUBLE) u4_wd / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; WORD32 i4_layer_luma_ht = ((DOUBLE) u4_ht / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; WORD32 i4_num_mbs_in_row = i4_layer_luma_wd / MB_SIZE; WORD32 i4_num_mbs_in_col = i4_layer_luma_ht / MB_SIZE; ps_top_mb_info = (isvce_mb_info_t *) pu1_buf; pu1_buf += (i4_num_mbs_in_row + 1) * i4_num_mbs_in_col * sizeof(ps_top_mb_info[0]); i8_alloc_mem_size -= (i4_num_mbs_in_row + 1) * i4_num_mbs_in_col * sizeof(ps_top_mb_info[0]); ps_top_intra_modes = (mb_intra_modes_t *) pu1_buf; pu1_buf += (i4_num_mbs_in_row + 1) * i4_num_mbs_in_col * sizeof(ps_top_intra_modes[0]); i8_alloc_mem_size -= (i4_num_mbs_in_row + 1) * i4_num_mbs_in_col * sizeof(ps_top_intra_modes[0]); for(j = 0; j < MAX_PROCESS_CTXT; j++) { ps_codec->as_process[j].s_nbr_info_base.ps_layer_nbr_info[i].ps_top_row_mb_info = ps_top_mb_info; ps_codec->as_process[j].s_nbr_info.ps_top_row_mb_info = NULL; ps_codec->as_process[j].s_nbr_info_base.ps_layer_nbr_info[i].ps_top_mb_intra_modes = ps_top_intra_modes; ps_codec->as_process[j].s_nbr_info.ps_top_mb_intra_modes = NULL; } ASSERT(i8_alloc_mem_size >= 0); } } /** ******************************************************************************* * * @brief * isvce_codec_t and proc_t initialisations for an Access Unit * * @par Description: * Before beginning to encode the frame, the current function initializes all * the ctxts (proc, entropy, me, ...) basing on the input configured params. * It locates space for storing recon in the encoder picture buffer set, fetches * reference frame from encoder picture buffer set. Calls RC pre-enc to get * qp and pic type for the current frame. Queues proc jobs so that * the other threads can begin encoding. In brief, this function sets up the * tone for the entire encoder. * * @param[in] ps_codec * Pointer to codec context * * @param[in] ps_inp_buf * Pointer to input buffer context * * @returns error_status * * @remarks * * ******************************************************************************* */ IH264E_ERROR_T isvce_svc_au_init(isvce_codec_t *ps_codec, isvce_inp_buf_t *ps_inp_buf) { svc_au_buf_t *ps_cur_pic; WORD32 cur_mv_bank_buf_id; WORD32 cur_pic_buf_id; WORD32 ref_set_id; WORD32 i, j; svc_au_data_t *ps_mv_buf = NULL; svc_au_buf_t *aps_ref_pic[MAX_REF_PIC_CNT] = {NULL, NULL}; svc_au_data_t *aps_mv_buf[MAX_REF_PIC_CNT] = {NULL, NULL}; IH264E_ERROR_T error_status = IH264E_SUCCESS; PIC_TYPE_T *pic_type = &ps_codec->pic_type; UWORD32 u4_timestamp_high = ps_inp_buf->s_inp_props.u4_timestamp_high; UWORD32 u4_timestamp_low = ps_inp_buf->s_inp_props.u4_timestamp_low; WORD32 ctxt_sel = ps_codec->i4_encode_api_call_cnt % MAX_CTXT_SETS; /* Diamond search Iteration Max Cnt */ UWORD32 u4_num_layers = (ps_codec->s_cfg.u4_enc_speed_preset == IVE_FASTEST) ? (NUM_LAYERS >> 2) : NUM_LAYERS; UWORD32 u4_enable_fast_sad = ps_codec->s_cfg.u4_enable_fast_sad; if((PIC_I == *pic_type) || (PIC_IDR == *pic_type)) { ps_codec->i4_slice_type = ISLICE; } else if(PIC_P == *pic_type) { ps_codec->i4_slice_type = PSLICE; } else if(PIC_B == *pic_type) { ps_codec->i4_slice_type = BSLICE; } ps_codec->u4_is_curr_frm_ref = 0; ps_codec->u4_is_curr_frm_ref = (*pic_type != PIC_B); if(ps_codec->s_cfg.u4_enable_alt_ref && (*pic_type == PIC_P) && (ps_codec->i4_pic_cnt % (ps_codec->s_cfg.u4_enable_alt_ref + 1))) { ps_codec->u4_is_curr_frm_ref = 0; } ps_codec->u4_is_idr = 0; if(PIC_IDR == *pic_type) { ps_codec->u4_is_idr = 1; ps_codec->i4_frame_num = 0; ps_codec->i4_idr_pic_id++; } ps_codec->u4_disable_deblock_level = 1; if(ps_codec->s_cfg.u4_disable_deblock_level == DISABLE_DEBLK_LEVEL_0) { ps_codec->u4_disable_deblock_level = 0; } else if(ps_codec->s_cfg.u4_disable_deblock_level == DISABLE_DEBLK_LEVEL_2) { if(ps_codec->u4_disable_deblock_level_cnt == DISABLE_DEBLOCK_INTERVAL || ps_codec->i4_slice_type == ISLICE) { ps_codec->u4_disable_deblock_level = 0; } } else if(ps_codec->s_cfg.u4_disable_deblock_level == DISABLE_DEBLK_LEVEL_3) { if(ps_codec->i4_slice_type == ISLICE) { ps_codec->u4_disable_deblock_level = 0; } } if(ps_codec->u4_disable_deblock_level) { ps_codec->u4_disable_deblock_level_cnt++; } else { ps_codec->u4_disable_deblock_level_cnt = 0; } if(ps_codec->u4_disable_deblock_level == 0) { if(ps_codec->s_cfg.e_slice_mode != IVE_SLICE_MODE_NONE) { ps_codec->i4_error_code = IH264E_SLICE_TYPE_INPUT_INVALID; return IH264E_SLICE_TYPE_INPUT_INVALID; } } ps_codec->i4_error_code = IH264E_SUCCESS; if(ps_codec->i4_gen_header) { sps_t *ps_sps = NULL; pps_t *ps_pps = NULL; subset_sps_t *ps_subset_sps = NULL; UWORD8 u1_profile_idc = IH264_PROFILE_BASELINE; if(ps_codec->as_process[ctxt_sel * MAX_PROCESS_THREADS].u1_spatial_layer_id > 0) { u1_profile_idc = IH264_SCALABLE_BASELINE; } ps_sps = ps_codec->ps_sps_base; isvce_populate_sps(ps_codec, ps_sps, 0, u1_profile_idc, ps_inp_buf, 0); ps_pps = ps_codec->ps_pps_base; isvce_populate_pps(ps_codec, ps_pps, 0, 0, 0); for(i = 1; i < ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers; i++) { ps_subset_sps = ps_codec->ps_subset_sps_base + i; isvce_populate_subset_sps(ps_codec, ps_subset_sps, i, ps_inp_buf, i); /* populate pps header */ ps_pps = ps_codec->ps_pps_base + i; isvce_populate_pps(ps_codec, ps_pps, i, i, i); } } if(IH264E_SUCCESS != isvce_ref_list_refresh(ps_codec, aps_ref_pic, aps_mv_buf, &ref_set_id, pic_type[0])) { ps_codec->i4_error_code = IH264E_NO_FREE_PICBUF; return IH264E_NO_FREE_PICBUF; } { ps_mv_buf = (svc_au_data_t *) ih264_buf_mgr_get_next_free( (buf_mgr_t *) ps_codec->pv_svc_au_data_store_mgr, &cur_mv_bank_buf_id); if(NULL == ps_mv_buf) { ps_codec->i4_error_code = IH264E_NO_FREE_MVBANK; return IH264E_NO_FREE_MVBANK; } if(ps_codec->u4_is_curr_frm_ref) { ih264_buf_mgr_set_status(ps_codec->pv_svc_au_data_store_mgr, cur_mv_bank_buf_id, BUF_MGR_REF); } ps_mv_buf->i4_abs_poc = ps_codec->i4_abs_pic_order_cnt; ps_mv_buf->i4_buf_id = cur_mv_bank_buf_id; } { ps_cur_pic = (svc_au_buf_t *) ih264_buf_mgr_get_next_free( (buf_mgr_t *) ps_codec->pv_ref_buf_mgr, &cur_pic_buf_id); if(NULL == ps_cur_pic) { ps_codec->i4_error_code = IH264E_NO_FREE_PICBUF; return IH264E_NO_FREE_PICBUF; } if(ps_codec->u4_is_curr_frm_ref) { ih264_buf_mgr_set_status(ps_codec->pv_ref_buf_mgr, cur_pic_buf_id, BUF_MGR_REF); } if(1 == ps_codec->s_cfg.u4_enable_recon) { ih264_buf_mgr_set_status(ps_codec->pv_ref_buf_mgr, cur_pic_buf_id, BUF_MGR_IO); } ps_cur_pic->u4_timestamp_high = ps_inp_buf->s_inp_props.u4_timestamp_high; ps_cur_pic->u4_timestamp_low = ps_inp_buf->s_inp_props.u4_timestamp_low; ps_cur_pic->i4_abs_poc = ps_codec->i4_poc; ps_cur_pic->i4_poc_lsb = ps_codec->i4_pic_order_cnt_lsb; ps_cur_pic->i4_frame_num = ps_codec->i4_frame_num; ps_cur_pic->i4_buf_id = cur_pic_buf_id; ps_cur_pic->i1_temporal_id = isvce_svc_temporal_id_compute( ps_codec->i4_poc, ps_codec->s_cfg.s_svc_params.u1_num_temporal_layers, pic_type[0]); } /* * Add the current picture to ref list independent of the fact that it is used * as reference or not. This is because, now recon is not in sync with output * hence we may need the current recon after some delay. By adding it to ref * list we can retrieve the recon any time we want. The information that it is * used for ref can still be found by checking the buffer status of pic buf. */ ps_codec->as_ref_set[ref_set_id].i4_pic_cnt = ps_codec->i4_pic_cnt; ps_codec->as_ref_set[ref_set_id].i4_poc = ps_codec->i4_poc; ps_codec->as_ref_set[ref_set_id].ps_svc_au_data = ps_mv_buf; ps_codec->as_ref_set[ref_set_id].ps_pic_buf = ps_cur_pic; ps_codec->s_svc_ilp_data.ps_svc_au_data = ps_mv_buf; { isvce_process_ctxt_t *ps_proc = NULL; j = ctxt_sel * MAX_PROCESS_THREADS; for(i = j; i < (j + MAX_PROCESS_THREADS); i++) { ps_proc = &ps_codec->as_process[i]; ps_proc->s_svc_params = ps_codec->s_cfg.s_svc_params; ps_proc->i4_frame_num = ps_codec->i4_frame_num; ps_proc->u4_is_idr = ps_codec->u4_is_idr; ps_proc->u4_idr_pic_id = ps_codec->i4_idr_pic_id; ps_proc->i4_slice_type = ps_codec->i4_slice_type; ps_proc->u4_half_x_offset = 0; ps_proc->u4_half_y_offset = 0; ps_proc->u4_half_xy_offset = 0; ps_proc->u4_disable_deblock_level = ps_codec->u4_disable_deblock_level; ps_proc->i4_cur_mv_bank_buf_id = cur_mv_bank_buf_id; ps_proc->ps_cur_pic = ps_cur_pic; ps_proc->ps_cur_mv_buf = ps_mv_buf; /* * pointer to ref picture * 0 : Temporal back reference * 1 : Temporal forward reference */ ps_proc->aps_ref_pic[L0] = aps_ref_pic[L0]; ps_proc->aps_ref_pic[L1] = aps_ref_pic[L1]; if(ps_codec->pic_type == PIC_B) { ps_proc->aps_mv_buf[L0] = aps_mv_buf[L0]; ps_proc->aps_mv_buf[L1] = aps_mv_buf[L1]; } else { /* * Else is dummy since for non B pic we does not need this * But an assignment here will help in not having a segfault * when we calcualte colpic in P slices */ ps_proc->aps_mv_buf[L0] = ps_mv_buf; ps_proc->aps_mv_buf[L1] = ps_mv_buf; } ps_proc->s_inp_buf = ps_inp_buf[0]; ps_proc->i4_encode_api_call_cnt = ps_codec->i4_encode_api_call_cnt; ps_proc->i4_pic_cnt = ps_codec->i4_pic_cnt; ps_proc->i4_error_code = 0; { isvce_entropy_ctxt_t *ps_entropy = &ps_proc->s_entropy; ps_entropy->i4_sof = 0; ps_entropy->i4_eof = 0; ps_entropy->ps_sps_base = ps_codec->ps_sps_base; ps_entropy->ps_pps_base = ps_codec->ps_pps_base; ps_entropy->pu1_slice_idx = ps_proc->pu1_slice_idx; ps_entropy->ps_svc_nalu_ext_base = ps_proc->ps_svc_nalu_ext_base; ps_entropy->ps_subset_sps_base = ps_proc->ps_subset_sps_base; ps_entropy->ps_slice_hdr_base = ps_proc->ps_slice_hdr_base; ps_entropy->ps_svc_slice_hdr_base = ps_proc->ps_svc_slice_hdr_base; ps_entropy->i4_abs_pic_order_cnt = ps_codec->i4_poc; ps_entropy->i1_transform_8x8_mode_flag = 0; ps_entropy->i4_error_code = IH264E_SUCCESS; ps_proc->s_entropy.u4_is_last = ps_inp_buf->s_inp_props.u4_is_last; ps_proc->s_entropy.i4_pic_cnt = ps_codec->i4_pic_cnt; ps_entropy->u4_timestamp_low = u4_timestamp_low; ps_entropy->u4_timestamp_high = u4_timestamp_high; } { isvce_me_ctxt_t *ps_me_ctxt = &ps_proc->s_me_ctxt; ps_me_ctxt->ai2_srch_boundaries[0] = ps_codec->s_cfg.u4_srch_rng_x; ps_me_ctxt->ai2_srch_boundaries[1] = ps_codec->s_cfg.u4_srch_rng_y; ps_me_ctxt->u4_half_x_offset = ps_proc->u4_half_x_offset; ps_me_ctxt->u4_half_y_offset = ps_proc->u4_half_y_offset; ps_me_ctxt->u4_half_xy_offset = ps_proc->u4_half_xy_offset; ps_me_ctxt->u4_enable_fast_sad = u4_enable_fast_sad; ps_me_ctxt->u4_enable_hpel = ps_codec->s_cfg.u4_enable_hpel; ps_me_ctxt->u4_num_layers = u4_num_layers; ps_me_ctxt->u4_me_speed_preset = ps_codec->s_cfg.u4_me_speed_preset; if((i == j) && (0 == ps_codec->i4_poc)) { isvce_init_mv_bits(ps_me_ctxt); } } ps_proc->ps_ngbr_avbl = &(ps_proc->s_ngbr_avbl); } } return error_status; } void isvce_init_quant_params(isvce_process_ctxt_t *ps_proc, WORD32 qp) { isvce_codec_t *ps_codec = ps_proc->ps_codec; /* quant params */ quant_params_t *ps_qp_params; /* ptr to forward quant threshold matrix */ const UWORD16 *pu2_thres_mat = NULL; /* ptr to forward scale matrix */ const UWORD16 *pu2_scale_mat = gu2_quant_scale_matrix_4x4; /* ptr to inverse scale matrix */ const UWORD16 *pu2_iscale_mat = gau2_ih264_iquant_scale_matrix_4x4; /* temp var */ UWORD32 u4_qp[3], u4_qp_div6, u4_qp_mod6; COMPONENT_TYPE plane; WORD32 i; UWORD32 u4_satdq_t; const UWORD16 *pu2_smat; /********************************************************************/ /* init quant params for all planes Y, U and V */ /********************************************************************/ /* luma qp */ u4_qp[Y] = qp; /* chroma qp * TODO_LATER : just in case if the chroma planes use different qp's this * needs to be corrected accordingly. */ u4_qp[U] = gu1_qpc_fqpi[qp]; u4_qp[V] = gu1_qpc_fqpi[qp]; plane = Y; while(plane <= V) { u4_qp_div6 = (u4_qp[plane] / 6); u4_qp_mod6 = (u4_qp[plane] % 6); ps_qp_params = ps_proc->ps_qp_params[plane]; /* mb qp */ ps_qp_params->u1_mb_qp = u4_qp[plane]; /* mb qp / 6 */ ps_qp_params->u1_qp_div = u4_qp_div6; /* mb qp % 6 */ ps_qp_params->u1_qp_rem = u4_qp_mod6; /* QP bits */ ps_qp_params->u1_qbits = QP_BITS_h264_4x4 + u4_qp_div6; /* forward scale matrix */ ps_qp_params->pu2_scale_mat = pu2_scale_mat + (u4_qp_mod6 * 16); /* threshold matrix & weight for quantization */ pu2_thres_mat = gu2_forward_quant_threshold_4x4 + (u4_qp_mod6 * 16); for(i = 0; i < 16; i++) { ps_qp_params->pu2_thres_mat[i] = pu2_thres_mat[i] >> (8 - u4_qp_div6); ps_qp_params->pu2_weigh_mat[i] = 16; } /* qp dependent rounding constant */ ps_qp_params->u4_dead_zone = gu4_forward_quant_round_factor_4x4[u4_qp_div6]; /* slice dependent rounding constant */ if(ps_proc->i4_slice_type != ISLICE && ps_proc->i4_slice_type != SISLICE) { ps_qp_params->u4_dead_zone >>= 1; } /* SATQD threshold for zero block prediction */ if(ps_codec->s_cfg.u4_enable_satqd) { pu2_smat = ps_qp_params->pu2_scale_mat; u4_satdq_t = ((1 << (ps_qp_params->u1_qbits)) - ps_qp_params->u4_dead_zone); ps_qp_params->pu2_sad_thrsh[0] = u4_satdq_t / MAX(pu2_smat[3], pu2_smat[11]); ps_qp_params->pu2_sad_thrsh[1] = u4_satdq_t / MAX(pu2_smat[1], pu2_smat[9]); ps_qp_params->pu2_sad_thrsh[2] = u4_satdq_t / pu2_smat[15]; ps_qp_params->pu2_sad_thrsh[3] = u4_satdq_t / pu2_smat[7]; ps_qp_params->pu2_sad_thrsh[4] = u4_satdq_t / MAX(pu2_smat[12], pu2_smat[14]); ps_qp_params->pu2_sad_thrsh[5] = u4_satdq_t / MAX(pu2_smat[4], pu2_smat[6]); ps_qp_params->pu2_sad_thrsh[6] = u4_satdq_t / pu2_smat[13]; ps_qp_params->pu2_sad_thrsh[7] = u4_satdq_t / pu2_smat[5]; ps_qp_params->pu2_sad_thrsh[8] = u4_satdq_t / MAX(MAX3(pu2_smat[0], pu2_smat[2], pu2_smat[8]), pu2_smat[10]); } /* inverse scale matrix */ ps_qp_params->pu2_iscale_mat = pu2_iscale_mat + (u4_qp_mod6 * 16); plane += 1; } } /** ******************************************************************************* * * @brief * isvce_codec_t and proc_t initialisations for an Access Unit * * @par Description: * Before beginning to encode the frame, the current function initializes all * the ctxts (proc, entropy, me, ...) basing on the input configured params. * It locates space for storing recon in the encoder picture buffer set, fetches * reference frame from encoder picture buffer set. Calls RC pre-enc to get * qp and pic type for the current frame. Queues proc jobs so that * the other threads can begin encoding. In brief, this function sets up the * tone for the entire encoder. * * @param[in] ps_codec * Pointer to codec context * * @param[in] ps_inp_buf * Pointer to input buffer context * * @param[in] u1_spatial_layer_id * Spatial Layer IDl 0 => Base layer * * @returns error_status * * @remarks * * ******************************************************************************* */ IH264E_ERROR_T isvce_svc_layer_pic_init(isvce_codec_t *ps_codec, isvce_inp_buf_t *ps_inp_buf, UWORD8 u1_spatial_layer_id) { WORD32 i; IH264E_ERROR_T error_status = IH264E_SUCCESS; IH264_ERROR_T ret = IH264_SUCCESS; PIC_TYPE_T e_pic_type = ps_codec->pic_type; ASSERT(MAX_CTXT_SETS == 1); for(i = 0; i < MAX_PROCESS_THREADS; i++) { isvce_process_ctxt_t *ps_proc = &ps_codec->as_process[i]; isvce_entropy_ctxt_t *ps_entropy = &ps_proc->s_entropy; isvce_deblk_ctxt_t *ps_deblk = &ps_proc->s_deblk_ctxt; isvce_me_ctxt_t *ps_me_ctxt = &ps_proc->s_me_ctxt; svc_au_buf_t *ps_cur_pic = ps_proc->ps_cur_pic; svc_au_buf_t *aps_ref_pic[MAX_REF_PIC_CNT] = {ps_proc->aps_ref_pic[L0], ps_proc->aps_ref_pic[L1]}; ps_proc->u1_spatial_layer_id = u1_spatial_layer_id; ps_proc->s_src_pic_buf_props = ps_inp_buf->as_layer_yuv_buf_props[u1_spatial_layer_id]; ps_proc->s_rec_pic_buf_props = ps_cur_pic->ps_layer_yuv_buf_props[u1_spatial_layer_id]; ASSERT(0 == (ps_inp_buf->as_layer_yuv_buf_props[u1_spatial_layer_id].u4_width % MB_SIZE)); ASSERT(0 == (ps_inp_buf->as_layer_yuv_buf_props[u1_spatial_layer_id].u4_height % MB_SIZE)); ps_proc->i4_wd_mbs = ps_inp_buf->as_layer_yuv_buf_props[u1_spatial_layer_id].u4_width / MB_SIZE; ps_proc->i4_ht_mbs = ps_inp_buf->as_layer_yuv_buf_props[u1_spatial_layer_id].u4_height / MB_SIZE; ps_proc->u1_frame_qp = ps_codec->au4_frame_qp[u1_spatial_layer_id]; ps_proc->u1_mb_qp = ps_proc->u1_frame_qp; ps_entropy->ps_mb_qp_ctxt->u1_cur_mb_qp = ps_proc->u1_frame_qp; isvce_init_quant_params(ps_proc, ps_proc->u1_frame_qp); memset(&ps_proc->s_frame_info, 0, sizeof(frame_info_t)); /* row '-1' */ memset(ps_proc->pu1_proc_map - ps_proc->i4_wd_mbs, 1, ps_proc->i4_wd_mbs * sizeof(ps_proc->pu1_proc_map[0])); /* row 0 to ht in mbs */ memset(ps_proc->pu1_proc_map, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs * sizeof(ps_proc->pu1_proc_map[0])); /* row '-1' */ memset(ps_proc->pu1_deblk_map - ps_proc->i4_wd_mbs, 1, ps_proc->i4_wd_mbs * sizeof(ps_proc->pu1_deblk_map[0])); /* row 0 to ht in mbs */ memset(ps_proc->pu1_deblk_map, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs * sizeof(ps_proc->pu1_deblk_map[0])); /* row '-1' */ memset(ps_proc->pu1_me_map - ps_proc->i4_wd_mbs, 1, ps_proc->i4_wd_mbs * sizeof(ps_proc->pu1_me_map[0])); /* row 0 to ht in mbs */ memset(ps_proc->pu1_me_map, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs * sizeof(ps_proc->pu1_me_map[0])); if(IVE_AIR_MODE_NONE != ps_codec->s_cfg.e_air_mode) { ps_codec->i4_air_pic_cnt = (ps_codec->i4_air_pic_cnt + 1) % ps_codec->s_cfg.u4_air_refresh_period; if(!ps_codec->i4_air_pic_cnt) { memset(ps_proc->pu1_is_intra_coded, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs * sizeof(ps_proc->pu1_is_intra_coded[0])); } } if(ps_codec->s_cfg.e_slice_mode == IVE_SLICE_MODE_NONE) { memset(ps_proc->pu1_slice_idx, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs * sizeof(ps_proc->pu1_slice_idx[0])); } else if(ps_codec->s_cfg.e_slice_mode == IVE_SLICE_MODE_BLOCKS) { UWORD8 *pu1_slice_idx = ps_proc->pu1_slice_idx; WORD32 i4_mb_y = 0, slice_idx = 0, cnt; while(i4_mb_y < ps_proc->i4_ht_mbs) { if(i4_mb_y + (WORD32) ps_codec->s_cfg.u4_slice_param < ps_proc->i4_ht_mbs) { cnt = ps_codec->s_cfg.u4_slice_param * ps_proc->i4_wd_mbs; i4_mb_y += ps_codec->s_cfg.u4_slice_param; } else { cnt = (ps_proc->i4_ht_mbs - i4_mb_y) * ps_proc->i4_wd_mbs; i4_mb_y += (ps_proc->i4_ht_mbs - i4_mb_y); } memset(pu1_slice_idx, slice_idx, cnt * sizeof(pu1_slice_idx[0])); slice_idx++; pu1_slice_idx += cnt; } } if((e_pic_type != PIC_IDR) && (e_pic_type != PIC_I)) { ps_proc->as_ref_pic_buf_props[L0] = aps_ref_pic[L0]->ps_layer_yuv_buf_props[u1_spatial_layer_id]; ps_proc->as_ref_pic_buf_props[L1] = aps_ref_pic[L1]->ps_layer_yuv_buf_props[u1_spatial_layer_id]; } ps_entropy->i4_gen_header = ps_codec->i4_gen_header && (0 == u1_spatial_layer_id); ps_entropy->i4_gen_subset_sps = (ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers > 1) && ps_codec->i4_gen_header; /* row '-1' */ memset(ps_entropy->pu1_entropy_map - ps_proc->i4_wd_mbs, 1, ps_proc->i4_wd_mbs * sizeof(ps_entropy->pu1_entropy_map[0])); /* row 0 to ht in mbs */ memset(ps_entropy->pu1_entropy_map, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs * sizeof(ps_entropy->pu1_entropy_map[0])); isvce_init_cabac_table(ps_entropy); ps_entropy->i4_wd_mbs = ps_proc->i4_wd_mbs; ps_entropy->i4_ht_mbs = ps_proc->i4_ht_mbs; ps_entropy->u1_entropy_coding_mode_flag = ((ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers > 1) && (0 == u1_spatial_layer_id)) ? CAVLC : ps_codec->s_cfg.u4_entropy_coding_mode; ps_proc->s_entropy.pi4_mb_skip_run[0] = 0; ps_entropy->u4_header_bits[MB_TYPE_INTRA] = 0; ps_entropy->u4_header_bits[MB_TYPE_INTER] = 0; ps_entropy->u4_residue_bits[MB_TYPE_INTRA] = 0; ps_entropy->u4_residue_bits[MB_TYPE_INTER] = 0; ps_entropy->u1_spatial_layer_id = ps_proc->u1_spatial_layer_id; ps_deblk->pu1_slice_idx = ps_proc->pu1_slice_idx; ps_me_ctxt->u1_mb_qp = ps_codec->au4_frame_qp[u1_spatial_layer_id]; { UWORD8 u1_min_qp; UWORD8 u1_max_qp; svc_sub_pic_rc_ctxt_t *ps_sub_pic_rc_ctxt = ps_proc->ps_sub_pic_rc_ctxt; svc_sub_pic_rc_layer_variables_t *ps_layer_variables = &ps_sub_pic_rc_ctxt->s_sub_pic_rc_variables.s_layer_variables; switch(ps_proc->i4_slice_type) { case ISLICE: { u1_min_qp = ps_codec->s_cfg.au4_i_qp_min[u1_spatial_layer_id]; u1_max_qp = ps_codec->s_cfg.au4_i_qp_max[u1_spatial_layer_id]; break; } case PSLICE: { u1_min_qp = ps_codec->s_cfg.au4_p_qp_min[u1_spatial_layer_id]; u1_max_qp = ps_codec->s_cfg.au4_p_qp_max[u1_spatial_layer_id]; break; } default: { u1_min_qp = ps_codec->s_cfg.au4_b_qp_min[u1_spatial_layer_id]; u1_max_qp = ps_codec->s_cfg.au4_b_qp_max[u1_spatial_layer_id]; break; } } ps_layer_variables->i4_max_num_reference_frames = ps_codec->i4_max_num_reference_frames; ps_layer_variables->i4_slice_type = ps_proc->i4_slice_type; ps_layer_variables->i4_frame_num = ps_proc->i4_frame_num; ps_layer_variables->u1_frame_qp = ps_proc->u1_frame_qp; ps_layer_variables->u1_spatial_layer_id = u1_spatial_layer_id; ps_layer_variables->u1_min_qp = u1_min_qp; ps_layer_variables->u1_max_qp = u1_max_qp; isvce_sub_pic_rc_ctxt_layer_init(ps_proc->ps_sub_pic_rc_ctxt); } } { job_t s_job; s_job.i4_cmd = CMD_PROCESS; s_job.i2_mb_cnt = ps_inp_buf->as_layer_yuv_buf_props[u1_spatial_layer_id].u4_width / MB_SIZE; s_job.i2_mb_x = 0; for(i = 0; i < (WORD32) (ps_inp_buf->as_layer_yuv_buf_props[u1_spatial_layer_id].u4_height / MB_SIZE); i++) { s_job.i2_mb_y = i; ret = ih264_list_queue(ps_codec->pv_proc_jobq, &s_job, 1); if(ret != IH264_SUCCESS) { ps_codec->i4_error_code = ret; return IH264E_FAIL; } } /* Once all the jobs are queued, terminate the queue */ /* Since the threads are created and deleted in each call, terminating here is not an issue */ ih264_list_terminate(ps_codec->pv_proc_jobq); } ps_codec->i4_gen_header = 0; return error_status; } /** ******************************************************************************* * * @brief initialize process context. * * @par Description: * Before dispatching the current job to process thread, the process context * associated with the job is initialized. Usually every job aims to encode one * row of mb's. Basing on the row indices provided by the job, the process * context's buffer ptrs, slice indices and other elements that are necessary * during core-coding are initialized. * * @param[in] ps_proc * Pointer to the current process context * * @returns error status * * @remarks none * ******************************************************************************* */ IH264E_ERROR_T isvce_init_layer_proc_ctxt(isvce_process_ctxt_t *ps_proc) { WORD32 i4_mb_x, i4_mb_y; isvce_codec_t *ps_codec = ps_proc->ps_codec; n_mb_process_ctxt_t *ps_n_mb_ctxt = &ps_proc->s_n_mb_ctxt; quant_params_t *ps_qp_params = ps_proc->ps_qp_params[0]; isvce_deblk_ctxt_t *ps_deblk = &ps_proc->s_deblk_ctxt; isvce_bs_ctxt_t *ps_bs = &(ps_deblk->s_bs_ctxt); svc_au_data_t *ps_cur_mv_buf = ps_proc->ps_cur_mv_buf; i4_mb_x = ps_proc->i4_mb_x; i4_mb_y = ps_proc->i4_mb_y; ASSERT((ps_codec->s_cfg.u4_wd - ps_codec->s_cfg.u4_disp_wd) == 0); ASSERT((ps_codec->s_cfg.u4_ht - ps_codec->s_cfg.u4_disp_ht) == 0); ps_proc->i4_nmb_ntrpy = ps_proc->i4_wd_mbs; ps_proc->u4_nmb_me = 1; ps_proc->s_src_buf_props = ps_proc->s_src_pic_buf_props; ps_proc->s_rec_buf_props = ps_proc->s_rec_pic_buf_props; ps_proc->as_ref_buf_props[0] = ps_proc->as_ref_pic_buf_props[0]; ps_proc->as_ref_buf_props[1] = ps_proc->as_ref_pic_buf_props[1]; ps_proc->s_src_buf_props.as_component_bufs[0].pv_data = ((UWORD8 *) ps_proc->s_src_buf_props.as_component_bufs[0].pv_data) + (i4_mb_x * MB_SIZE) + ps_proc->s_src_buf_props.as_component_bufs[0].i4_data_stride * (i4_mb_y * MB_SIZE); ps_proc->s_src_buf_props.as_component_bufs[1].pv_data = ((UWORD8 *) ps_proc->s_src_pic_buf_props.as_component_bufs[1].pv_data) + (i4_mb_x * MB_SIZE) + ps_proc->s_src_buf_props.as_component_bufs[1].i4_data_stride * (i4_mb_y * BLK8x8SIZE); ps_proc->s_rec_buf_props.as_component_bufs[0].pv_data = ((UWORD8 *) ps_proc->s_rec_buf_props.as_component_bufs[0].pv_data) + (i4_mb_x * MB_SIZE) + ps_proc->s_rec_buf_props.as_component_bufs[0].i4_data_stride * (i4_mb_y * MB_SIZE); ps_proc->s_rec_buf_props.as_component_bufs[1].pv_data = ((UWORD8 *) ps_proc->s_rec_buf_props.as_component_bufs[1].pv_data) + (i4_mb_x * MB_SIZE) + ps_proc->s_rec_buf_props.as_component_bufs[1].i4_data_stride * (i4_mb_y * BLK8x8SIZE); ps_proc->as_ref_buf_props[0].as_component_bufs[0].pv_data = ((UWORD8 *) ps_proc->as_ref_buf_props[0].as_component_bufs[0].pv_data) + (i4_mb_x * MB_SIZE) + ps_proc->as_ref_buf_props[0].as_component_bufs[0].i4_data_stride * (i4_mb_y * MB_SIZE); ps_proc->as_ref_buf_props[0].as_component_bufs[1].pv_data = ((UWORD8 *) ps_proc->as_ref_buf_props[0].as_component_bufs[1].pv_data) + (i4_mb_x * MB_SIZE) + ps_proc->as_ref_buf_props[0].as_component_bufs[1].i4_data_stride * (i4_mb_y * BLK8x8SIZE); ps_proc->as_ref_buf_props[1].as_component_bufs[0].pv_data = ((UWORD8 *) ps_proc->as_ref_buf_props[1].as_component_bufs[0].pv_data) + (i4_mb_x * MB_SIZE) + ps_proc->as_ref_buf_props[1].as_component_bufs[0].i4_data_stride * (i4_mb_y * MB_SIZE); ps_proc->as_ref_buf_props[1].as_component_bufs[1].pv_data = ((UWORD8 *) ps_proc->as_ref_buf_props[1].as_component_bufs[1].pv_data) + (i4_mb_x * MB_SIZE) + ps_proc->as_ref_buf_props[1].as_component_bufs[1].i4_data_stride * (i4_mb_y * BLK8x8SIZE); ps_proc->pv_mb_coeff_data = ((UWORD8 *) ps_proc->pv_pic_mb_coeff_data) + i4_mb_y * ps_codec->u4_size_coeff_data; ps_proc->pv_mb_header_data = ((UWORD8 *) ps_proc->pv_pic_mb_header_data) + i4_mb_y * ps_codec->u4_size_header_data; ps_proc->i4_cur_slice_idx = ps_proc->pu1_slice_idx[i4_mb_y * ps_proc->i4_wd_mbs + i4_mb_x]; ps_proc->ps_mb_info = ps_cur_mv_buf->ps_svc_layer_data[ps_proc->u1_spatial_layer_id].ps_mb_info + i4_mb_y * ps_proc->i4_wd_mbs; ps_proc->ps_col_mb = ps_proc->aps_mv_buf[1]->ps_svc_layer_data[ps_proc->u1_spatial_layer_id].ps_mb_info + i4_mb_y * ps_proc->i4_wd_mbs; { ps_proc->s_nbr_info.ps_top_row_mb_info = ps_proc->s_nbr_info_base.ps_layer_nbr_info[ps_proc->u1_spatial_layer_id] .ps_top_row_mb_info + (i4_mb_x + (i4_mb_y - 1) * ps_proc->i4_wd_mbs); ps_proc->s_nbr_info.ps_top_mb_intra_modes = ps_proc->s_nbr_info_base.ps_layer_nbr_info[ps_proc->u1_spatial_layer_id] .ps_top_mb_intra_modes + (i4_mb_x + (i4_mb_y - 1) * ps_proc->i4_wd_mbs); } ps_proc->pu4_mb_pu_cnt = ps_cur_mv_buf->ps_svc_layer_data[ps_proc->u1_spatial_layer_id].pu4_num_pus_in_mb + (i4_mb_y * ps_proc->i4_wd_mbs); ps_proc->ps_mb_info->u2_mb_type = I16x16; ps_proc->u4_lambda = gu1_qp0[ps_qp_params->u1_mb_qp]; ps_proc->i4_mb_distortion = SHRT_MAX; if(i4_mb_x == 0) { ps_proc->s_nbr_info.ps_left_mb_info[0].i4_mb_distortion = 0; } ps_proc->i4_mb_cost = INT_MAX; ps_deblk->i4_mb_x = ps_proc->i4_mb_x; /* deblk lags the current mb proc by 1 row */ /* NOTE: Intra prediction has to happen with non deblocked samples used as * reference */ /* Hence to deblk MB 0 of row 0, you have wait till MB 0 of row 1 is encoded. */ /* For simplicity, we chose to lag deblking by 1 Row wrt to proc */ ps_deblk->i4_mb_y = ps_proc->i4_mb_y - 1; ps_deblk->s_rec_pic_buf_props = ps_proc->s_rec_pic_buf_props; ps_bs->i4_mb_x = ps_proc->i4_mb_x; ps_bs->i4_mb_y = ps_proc->i4_mb_y; ps_n_mb_ctxt->i4_mb_x = 0; ps_n_mb_ctxt->i4_mb_y = ps_deblk->i4_mb_y; ps_n_mb_ctxt->i4_n_mbs = ps_proc->i4_nmb_ntrpy; return IH264E_SUCCESS; } /** ******************************************************************************* * * @brief * Returns size of buffers for storing SVC ILP data * * @param[in] u1_num_spatial_layers * Num Spatial Layers * * @param[in] d_spatial_res_ratio * Resolution Ratio b/w spatial layers * * @param[in] u4_wd * Input Width * * @param[in] u4_ht * Input Height * * @returns Size of buffers * ******************************************************************************* */ UWORD32 isvce_get_svc_ilp_buf_size(UWORD8 u1_num_spatial_layers, DOUBLE d_spatial_res_ratio, UWORD32 u4_wd, UWORD32 u4_ht) { WORD32 i; UWORD32 u4_size = 0; if(u1_num_spatial_layers > 1) { /* ps_intra_recon_bufs */ u4_size += u1_num_spatial_layers * sizeof(yuv_buf_props_t); /* ps_residual_bufs */ u4_size += u1_num_spatial_layers * sizeof(yuv_buf_props_t); /* aps_layer_resampler_props[Y] */ u4_size += u1_num_spatial_layers * sizeof(layer_resampler_props_t); /* aps_layer_resampler_props[UV] */ u4_size += u1_num_spatial_layers * sizeof(layer_resampler_props_t); for(i = u1_num_spatial_layers - 1; i >= 0; i--) { WORD32 i4_layer_luma_wd = ((DOUBLE) u4_wd / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; WORD32 i4_layer_luma_ht = ((DOUBLE) u4_ht / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; WORD32 i4_layer_luma_samples = (ALIGN16(i4_layer_luma_wd) + PAD_WD) * (i4_layer_luma_ht + PAD_HT); WORD32 i4_layer_uv_wd = i4_layer_luma_wd; WORD32 i4_layer_uv_ht = i4_layer_luma_ht / 2.0 + 0.99; WORD32 i4_layer_uv_samples = (ALIGN16(i4_layer_uv_wd) + PAD_WD) * (i4_layer_uv_ht + PAD_HT); /* ps_intra_recon_bufs */ u4_size += (i4_layer_luma_samples + i4_layer_uv_samples) * sizeof(UWORD8); /* ps_residual_bufs */ u4_size += (i4_layer_luma_samples + i4_layer_uv_samples) * sizeof(WORD16); } } else { WORD32 i4_layer_luma_wd = u4_wd; WORD32 i4_layer_luma_ht = u4_ht; WORD32 i4_layer_luma_samples = (ALIGN16(i4_layer_luma_wd) + PAD_WD) * (i4_layer_luma_ht + PAD_HT); WORD32 i4_layer_uv_wd = i4_layer_luma_wd; WORD32 i4_layer_uv_ht = i4_layer_luma_ht / 2.0 + 0.99; WORD32 i4_layer_uv_samples = (ALIGN16(i4_layer_uv_wd) + PAD_WD) * (i4_layer_uv_ht + PAD_HT); /* ps_residual_bufs */ u4_size += sizeof(yuv_buf_props_t); /* ps_residual_bufs */ u4_size += (i4_layer_luma_samples + i4_layer_uv_samples) * sizeof(WORD16); } return u4_size; } static void isvce_layer_resampler_props_init(layer_resampler_props_t *ps_layer_props, DOUBLE d_spatial_res_ratio, UWORD32 u4_wd, UWORD32 u4_ht, UWORD8 u1_level_idc, UWORD8 u1_is_chroma) { const UWORD8 u1_ref_layer_field_pic_flag = 0; const UWORD8 u1_field_pic_flag = 0; const UWORD8 u1_frame_mbs_only_flag = 1; const UWORD8 u1_ref_layer_frame_mbs_only_flag = 1; const UWORD8 u1_bot_field_flag = 0; const WORD32 i4_scaled_ref_layer_left_offset = 0; const WORD32 i4_scaled_ref_layer_top_offset = 0; const WORD32 i4_ref_layer_chroma_phase_x_plus1 = 1; const WORD32 i4_ref_layer_chroma_phase_y_plus1 = 1; const WORD32 i4_chroma_phase_x_plus1 = 1; const WORD32 i4_chroma_phase_y_plus1 = 1; const WORD32 i4_sub_wd_chroma = 2; const WORD32 i4_sub_ht_chroma = 2; UWORD32 u4_ref_wd = (u4_wd / d_spatial_res_ratio); UWORD32 u4_ref_ht = (u4_ht / d_spatial_res_ratio) * (1 + u1_ref_layer_field_pic_flag); UWORD32 u4_scaled_wd = u4_wd; UWORD32 u4_scaled_ht = u4_ht * (1 + u1_field_pic_flag); u4_ref_wd = u4_ref_wd >> u1_is_chroma; u4_ref_ht = u4_ref_ht >> u1_is_chroma; u4_scaled_wd = u4_scaled_wd >> u1_is_chroma; u4_scaled_ht = u4_scaled_ht >> u1_is_chroma; if(u1_is_chroma) { ps_layer_props->i4_refphase_x = i4_ref_layer_chroma_phase_x_plus1 - 1; ps_layer_props->i4_refphase_y = i4_ref_layer_chroma_phase_y_plus1 - 1; ps_layer_props->i4_phase_x = i4_chroma_phase_x_plus1 - 1; ps_layer_props->i4_phase_y = i4_chroma_phase_y_plus1 - 1; ps_layer_props->u4_sub_wd = i4_sub_wd_chroma; ps_layer_props->u4_sub_ht = i4_sub_ht_chroma; ps_layer_props->u4_mb_wd = MB_SIZE >> 1; ps_layer_props->u4_mb_ht = MB_SIZE >> 1; } else { ps_layer_props->i4_refphase_x = 0; ps_layer_props->i4_refphase_y = 0; ps_layer_props->i4_phase_x = 0; ps_layer_props->i4_phase_y = 0; ps_layer_props->u4_sub_wd = 1; ps_layer_props->u4_sub_ht = 1; ps_layer_props->u4_mb_wd = MB_SIZE; ps_layer_props->u4_mb_ht = MB_SIZE; } if(u1_level_idc <= 30) { ps_layer_props->u4_shift_x = 16; ps_layer_props->u4_shift_y = 16; } else { ps_layer_props->u4_shift_x = 31 - isvcd_get_ceil_log2(u4_ref_wd); ps_layer_props->u4_shift_y = 31 - isvcd_get_ceil_log2(u4_ref_ht); } if((0 == u1_frame_mbs_only_flag) || (0 == u1_ref_layer_frame_mbs_only_flag)) { ps_layer_props->i4_phase_y = ps_layer_props->i4_phase_y + 4 * u1_bot_field_flag; if(1 == u1_ref_layer_frame_mbs_only_flag) { ps_layer_props->i4_refphase_y = (2 * ps_layer_props->i4_refphase_y) + 2; } else { ps_layer_props->i4_refphase_y = ps_layer_props->i4_refphase_y + (4 * u1_bot_field_flag); } } ps_layer_props->u4_scale_x = ((u4_ref_wd << ps_layer_props->u4_shift_x) + (u4_scaled_wd >> 1)) / (u4_scaled_wd); ps_layer_props->u4_scale_y = ((u4_ref_ht << ps_layer_props->u4_shift_y) + (u4_scaled_ht >> 1)) / (u4_scaled_ht); ps_layer_props->i4_offset_x = i4_scaled_ref_layer_left_offset / ps_layer_props->u4_sub_wd; ps_layer_props->i4_add_x = (((u4_ref_wd * (2 + ps_layer_props->i4_phase_x)) << (ps_layer_props->u4_shift_x - 2)) + (u4_scaled_wd >> 1)) / u4_scaled_wd + (1 << (ps_layer_props->u4_shift_x - 5)); ps_layer_props->i4_delta_x = 4 * (2 + ps_layer_props->i4_refphase_x); if((1 == u1_frame_mbs_only_flag) && (1 == u1_ref_layer_frame_mbs_only_flag)) { ps_layer_props->i4_offset_y = i4_scaled_ref_layer_top_offset / ps_layer_props->u4_sub_ht; ps_layer_props->i4_add_y = (((u4_ref_ht * (2 + ps_layer_props->i4_phase_y)) << (ps_layer_props->u4_shift_y - 2)) + (u4_scaled_ht >> 1)) / u4_scaled_ht + (1 << (ps_layer_props->u4_shift_y - 5)); ps_layer_props->i4_delta_y = 4 * (2 + ps_layer_props->i4_refphase_y); } else { ps_layer_props->i4_offset_y = i4_scaled_ref_layer_top_offset / (2 * ps_layer_props->u4_sub_ht); ps_layer_props->i4_add_y = (((u4_ref_ht * (2 + ps_layer_props->i4_phase_y)) << (ps_layer_props->u4_shift_y - 3)) + (u4_scaled_ht >> 1)) / u4_scaled_ht + (1 << (ps_layer_props->u4_shift_y - 5)); ps_layer_props->i4_delta_y = 2 * (2 + ps_layer_props->i4_refphase_y); } } /** ******************************************************************************* * * @brief * Function to initialize svc ilp buffers * * @param[in] ps_codec * Pointer to codec context * * @param[in] ps_mem_rec * Pointer to memory allocated for input buffers * ******************************************************************************* */ void isvce_svc_ilp_buf_init(isvce_codec_t *ps_codec, iv_mem_rec_t *ps_mem_rec) { UWORD8 u1_num_spatial_layers = ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers; DOUBLE d_spatial_res_ratio = ps_codec->s_cfg.s_svc_params.d_spatial_res_ratio; UWORD32 u4_wd = ps_codec->s_cfg.u4_wd; UWORD32 u4_ht = ps_codec->s_cfg.u4_ht; UWORD8 *pu1_buf = ps_mem_rec->pv_base; WORD64 i8_alloc_mem_size = isvce_get_svc_ilp_buf_size(u1_num_spatial_layers, d_spatial_res_ratio, u4_wd, u4_ht); if(u1_num_spatial_layers > 1) { WORD32 i, j; ps_codec->s_svc_ilp_data.ps_intra_recon_bufs = (yuv_buf_props_t *) pu1_buf; pu1_buf += u1_num_spatial_layers * sizeof(ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[0]); i8_alloc_mem_size -= u1_num_spatial_layers * sizeof(ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[0]); ps_codec->s_svc_ilp_data.ps_residual_bufs = (yuv_buf_props_t *) pu1_buf; pu1_buf += u1_num_spatial_layers * sizeof(ps_codec->s_svc_ilp_data.ps_residual_bufs[0]); i8_alloc_mem_size -= u1_num_spatial_layers * sizeof(ps_codec->s_svc_ilp_data.ps_residual_bufs[0]); for(i = 0; i < NUM_SP_COMPONENTS; i++) { ps_codec->s_svc_ilp_data.aps_layer_resampler_props[i] = (layer_resampler_props_t *) pu1_buf; pu1_buf += u1_num_spatial_layers * sizeof(ps_codec->s_svc_ilp_data.aps_layer_resampler_props[i][0]); i8_alloc_mem_size -= u1_num_spatial_layers * sizeof(ps_codec->s_svc_ilp_data.aps_layer_resampler_props[i][0]); } ASSERT(i8_alloc_mem_size >= 0); for(i = u1_num_spatial_layers - 1; i >= 0; i--) { WORD32 i4_stride; WORD32 i4_layer_luma_wd = ((DOUBLE) u4_wd / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; WORD32 i4_layer_luma_ht = ((DOUBLE) u4_ht / pow(d_spatial_res_ratio, u1_num_spatial_layers - 1 - i)) + 0.99; WORD32 i4_layer_luma_samples = (ALIGN16(i4_layer_luma_wd) + PAD_WD) * (i4_layer_luma_ht + PAD_HT); WORD32 i4_layer_uv_wd = i4_layer_luma_wd; WORD32 i4_layer_uv_ht = i4_layer_luma_ht / 2.0 + 0.99; WORD32 i4_layer_uv_samples = (ALIGN16(i4_layer_uv_wd) + PAD_WD) * (i4_layer_uv_ht + PAD_HT); ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[i].u4_width = i4_layer_luma_wd; ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[i].u4_height = i4_layer_luma_ht; ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[i].e_color_format = IV_YUV_420SP_UV; ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[i].u1_bit_depth = 8; i4_stride = ALIGN16(i4_layer_luma_wd) + PAD_WD; ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[i].as_component_bufs[Y].pv_data = pu1_buf + PAD_LEFT + PAD_TOP * i4_stride; ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[i].as_component_bufs[Y].i4_data_stride = ALIGN16(i4_layer_luma_wd) + PAD_WD; pu1_buf += i4_layer_luma_samples * sizeof(UWORD8); i8_alloc_mem_size -= i4_layer_luma_samples * sizeof(UWORD8); i4_stride = ALIGN16(i4_layer_uv_wd) + PAD_WD; ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[i].as_component_bufs[UV].pv_data = pu1_buf + PAD_LEFT + PAD_TOP * i4_stride; ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[i].as_component_bufs[UV].i4_data_stride = ALIGN16(i4_layer_uv_wd) + PAD_WD; pu1_buf += i4_layer_uv_samples * sizeof(UWORD8); i8_alloc_mem_size -= i4_layer_uv_samples * sizeof(UWORD8); ps_codec->s_svc_ilp_data.ps_residual_bufs[i].u4_width = i4_layer_luma_wd; ps_codec->s_svc_ilp_data.ps_residual_bufs[i].u4_height = i4_layer_luma_ht; ps_codec->s_svc_ilp_data.ps_residual_bufs[i].e_color_format = IV_YUV_420SP_UV; ps_codec->s_svc_ilp_data.ps_residual_bufs[i].u1_bit_depth = 10; i4_stride = ALIGN16(i4_layer_luma_wd) + PAD_WD; ps_codec->s_svc_ilp_data.ps_residual_bufs[i].as_component_bufs[Y].pv_data = pu1_buf + (PAD_LEFT + PAD_TOP * i4_stride) * (sizeof(WORD16) / sizeof(pu1_buf[0])); ps_codec->s_svc_ilp_data.ps_residual_bufs[i].as_component_bufs[Y].i4_data_stride = i4_stride; pu1_buf += i4_layer_luma_samples * sizeof(WORD16); i8_alloc_mem_size -= i4_layer_luma_samples * sizeof(WORD16); i4_stride = ALIGN16(i4_layer_uv_wd) + PAD_WD; ps_codec->s_svc_ilp_data.ps_residual_bufs[i].as_component_bufs[UV].pv_data = pu1_buf + (PAD_LEFT + PAD_TOP * i4_stride) * (sizeof(WORD16) / sizeof(pu1_buf[0])); ps_codec->s_svc_ilp_data.ps_residual_bufs[i].as_component_bufs[UV].i4_data_stride = i4_stride; pu1_buf += i4_layer_uv_samples * sizeof(WORD16); i8_alloc_mem_size -= i4_layer_uv_samples * sizeof(WORD16); ps_codec->s_svc_ilp_data.ps_residual_bufs[i].as_component_bufs[V].pv_data = NULL; ASSERT(i8_alloc_mem_size >= 0); if(i >= 1) { for(j = 0; j < NUM_SP_COMPONENTS; j++) { isvce_layer_resampler_props_init( &ps_codec->s_svc_ilp_data.aps_layer_resampler_props[j][i], d_spatial_res_ratio, i4_layer_luma_wd, i4_layer_luma_ht, ps_codec->s_cfg.u4_max_level, ((COMPONENT_TYPE) j) == UV); } } } } else { WORD32 i4_stride; WORD32 i4_layer_luma_wd = u4_wd; WORD32 i4_layer_luma_ht = u4_ht; WORD32 i4_layer_luma_samples = (ALIGN16(i4_layer_luma_wd) + PAD_WD) * (i4_layer_luma_ht + PAD_HT); WORD32 i4_layer_uv_wd = i4_layer_luma_wd; WORD32 i4_layer_uv_ht = i4_layer_luma_ht / 2.0 + 0.99; WORD32 i4_layer_uv_samples = (ALIGN16(i4_layer_uv_wd) + PAD_WD) * (i4_layer_uv_ht + PAD_HT); ps_codec->s_svc_ilp_data.ps_residual_bufs = (yuv_buf_props_t *) pu1_buf; pu1_buf += sizeof(ps_codec->s_svc_ilp_data.ps_residual_bufs[0]); i8_alloc_mem_size -= sizeof(ps_codec->s_svc_ilp_data.ps_residual_bufs[0]); ASSERT(i8_alloc_mem_size >= 0); ps_codec->s_svc_ilp_data.ps_residual_bufs[0].u4_width = i4_layer_luma_wd; ps_codec->s_svc_ilp_data.ps_residual_bufs[0].u4_height = i4_layer_luma_ht; ps_codec->s_svc_ilp_data.ps_residual_bufs[0].e_color_format = IV_YUV_420SP_UV; ps_codec->s_svc_ilp_data.ps_residual_bufs[0].u1_bit_depth = 10; i4_stride = ALIGN16(i4_layer_luma_wd) + PAD_WD; ps_codec->s_svc_ilp_data.ps_residual_bufs[0].as_component_bufs[Y].pv_data = pu1_buf + (PAD_LEFT + PAD_TOP * i4_stride) * (sizeof(WORD16) / sizeof(pu1_buf[0])); ps_codec->s_svc_ilp_data.ps_residual_bufs[0].as_component_bufs[Y].i4_data_stride = i4_stride; pu1_buf += i4_layer_luma_samples * sizeof(WORD16); i8_alloc_mem_size -= i4_layer_luma_samples * sizeof(WORD16); i4_stride = ALIGN16(i4_layer_uv_wd) + PAD_WD; ps_codec->s_svc_ilp_data.ps_residual_bufs[0].as_component_bufs[UV].pv_data = pu1_buf + (PAD_LEFT + PAD_TOP * i4_stride) * (sizeof(WORD16) / sizeof(pu1_buf[0])); ps_codec->s_svc_ilp_data.ps_residual_bufs[0].as_component_bufs[UV].i4_data_stride = i4_stride; pu1_buf += i4_layer_uv_samples * sizeof(WORD16); i8_alloc_mem_size -= i4_layer_uv_samples * sizeof(WORD16); ps_codec->s_svc_ilp_data.ps_residual_bufs[0].as_component_bufs[V].pv_data = NULL; ASSERT(i8_alloc_mem_size >= 0); } } static FORCEINLINE UWORD32 isvce_get_residual_csbf(mem_fxns_t *ps_mem_fxns, buffer_container_t *ps_comp_buf) { WORD32 i; UWORD32 u4_csbf = 0; for(i = 0; i < MAX_TU_IN_MB; i++) { UWORD8 u1_zscan_idx = gau1_raster_to_zscan_map[i]; UWORD8 u1_offset_x = (i % MAX_TU_IN_MB_ROW) * MIN_TU_SIZE; UWORD8 u1_offset_y = (i / MAX_TU_IN_MB_ROW) * MIN_TU_SIZE; WORD16 *pi2_res = ((WORD16 *) ps_comp_buf->pv_data) + u1_offset_x + u1_offset_y * ps_comp_buf->i4_data_stride; UWORD8 u1_cbf = ps_mem_fxns->pf_nonzero_checker( (UWORD8 *) pi2_res, ps_comp_buf->i4_data_stride * (sizeof(WORD16) / sizeof(UWORD8)), MIN_TU_SIZE * (sizeof(WORD16) / sizeof(UWORD8)), MIN_TU_SIZE); u4_csbf |= (u1_cbf << u1_zscan_idx); } return u4_csbf; } /** ******************************************************************************* * * @brief * Function to update svc ilp buffers after every MB * * @param[in] ps_proc * Pointer to process context * ******************************************************************************* */ void isvce_svc_ilp_buf_update(isvce_process_ctxt_t *ps_proc) { isvce_codec_t *ps_codec = ps_proc->ps_codec; svc_params_t *ps_svc_params = &ps_codec->s_cfg.s_svc_params; UWORD8 u1_spatial_layer_id = ps_proc->u1_spatial_layer_id; if(ps_svc_params->u1_num_spatial_layers > 1) { buffer_container_t s_src; buffer_container_t s_dst; WORD32 i; svc_ilp_data_t *ps_svc_ilp_data = &ps_codec->s_svc_ilp_data; isa_dependent_fxns_t *ps_isa_dependent_fxns = &ps_codec->s_isa_dependent_fxns; mem_fxns_t *ps_mem_fxns = &ps_isa_dependent_fxns->s_mem_fxns; yuv_buf_props_t *ps_residual_buf = &ps_codec->s_svc_ilp_data.ps_residual_bufs[u1_spatial_layer_id]; WORD32 i4_mb_x = ps_proc->i4_mb_x; WORD32 i4_mb_y = ps_proc->i4_mb_y; ASSERT(ps_proc->s_rec_buf_props.e_color_format == IV_YUV_420SP_UV); if(u1_spatial_layer_id < (ps_svc_params->u1_num_spatial_layers - 1)) { if(ps_proc->ps_mb_info->u1_is_intra) { for(i = 0; i < NUM_SP_COMPONENTS; i++) { UWORD8 u1_is_chroma = (Y != ((COMPONENT_TYPE) i)); s_src = ps_proc->s_rec_buf_props.as_component_bufs[i]; s_dst.i4_data_stride = ps_svc_ilp_data->ps_intra_recon_bufs[u1_spatial_layer_id] .as_component_bufs[i] .i4_data_stride; s_dst.pv_data = ((UWORD8 *) ps_svc_ilp_data->ps_intra_recon_bufs[u1_spatial_layer_id] .as_component_bufs[i] .pv_data) + i4_mb_x * MB_SIZE + i4_mb_y * (MB_SIZE >> u1_is_chroma) * s_dst.i4_data_stride; ps_mem_fxns->pf_copy_2d((UWORD8 *) s_dst.pv_data, s_dst.i4_data_stride, (UWORD8 *) s_src.pv_data, s_src.i4_data_stride, MB_SIZE, (MB_SIZE >> u1_is_chroma)); } } else { for(i = 0; i < NUM_SP_COMPONENTS; i++) { UWORD8 u1_is_chroma = (Y != ((COMPONENT_TYPE) i)); s_dst.i4_data_stride = ps_svc_ilp_data->ps_intra_recon_bufs[u1_spatial_layer_id] .as_component_bufs[i] .i4_data_stride; s_dst.pv_data = ((UWORD8 *) ps_svc_ilp_data->ps_intra_recon_bufs[u1_spatial_layer_id] .as_component_bufs[i] .pv_data) + i4_mb_x * MB_SIZE + i4_mb_y * (MB_SIZE >> u1_is_chroma) * s_dst.i4_data_stride; ps_mem_fxns->pf_memset_2d((UWORD8 *) s_dst.pv_data, s_dst.i4_data_stride, 0, MB_SIZE, (MB_SIZE >> u1_is_chroma)); } } } if(ENABLE_RESIDUAL_PREDICTION && (ps_proc->i4_slice_type != ISLICE) && (u1_spatial_layer_id < (ps_svc_params->u1_num_spatial_layers - 1))) { if(ps_proc->ps_mb_info->u1_is_intra || (ps_proc->ps_mb_info->u2_mb_type == PSKIP) || (ps_proc->ps_mb_info->u2_mb_type == BSKIP)) { for(i = 0; i < NUM_SP_COMPONENTS; i++) { buffer_container_t *ps_comp_buf; WORD16 *pi2_res; UWORD8 u1_is_chroma = (Y != ((COMPONENT_TYPE) i)); ps_comp_buf = &ps_residual_buf->as_component_bufs[u1_is_chroma ? UV : Y]; pi2_res = ((WORD16 *) ps_comp_buf->pv_data) + ps_proc->i4_mb_x * MB_SIZE + ps_proc->i4_mb_y * (MB_SIZE >> u1_is_chroma) * ps_comp_buf->i4_data_stride; ps_mem_fxns->pf_memset_2d( (UWORD8 *) pi2_res, ps_comp_buf->i4_data_stride * (sizeof(WORD16) / sizeof(UWORD8)), 0, MB_SIZE * (sizeof(WORD16) / sizeof(UWORD8)), MB_SIZE >> u1_is_chroma); } } } if(ENABLE_RESIDUAL_PREDICTION && (u1_spatial_layer_id > 0) && !(ps_proc->ps_mb_info->u1_is_intra || (ps_proc->ps_mb_info->u2_mb_type == PSKIP) || (ps_proc->ps_mb_info->u2_mb_type == BSKIP))) { s_src = ps_residual_buf->as_component_bufs[Y]; s_src.pv_data = ((WORD16 *) s_src.pv_data) + ps_proc->i4_mb_x * MB_SIZE + ps_proc->i4_mb_y * MB_SIZE * s_src.i4_data_stride; ps_proc->ps_mb_info->u4_res_csbp = isvce_get_residual_csbf(ps_mem_fxns, &s_src); } else { ps_proc->ps_mb_info->u4_res_csbp = 0; } } else { ps_proc->ps_mb_info->u4_res_csbp = 0; } } /* * Padding has a one MB row dependency on deblock which * in turn has a one MB row dependency on encode */ static IH264E_ERROR_T isvce_pad_frame(isvce_process_ctxt_t *ps_proc, yuv_buf_props_t *ps_pad_buf) { /* codec context */ isvce_codec_t *ps_codec = ps_proc->ps_codec; WORD32 i4_element_size = (ps_pad_buf->u1_bit_depth > 8) ? 2 : 1; /* src buffers luma */ WORD32 i4_luma_stride = ps_pad_buf->as_component_bufs[0].i4_data_stride * i4_element_size; UWORD8 *pu1_curr_pic_luma = (UWORD8 *) (ps_pad_buf->as_component_bufs[0].pv_data); /* src buffers chroma */ WORD32 i4_chroma_stride = ps_pad_buf->as_component_bufs[1].i4_data_stride * i4_element_size; UWORD8 *pu1_curr_pic_chroma = (UWORD8 *) (ps_pad_buf->as_component_bufs[1].pv_data); WORD32 i4_bottom_offset_luma = ps_pad_buf->u4_height * i4_luma_stride; WORD32 i4_bottom_offset_chroma = (ps_pad_buf->u4_height >> 1) * i4_chroma_stride; /* Pad left */ ps_codec->pf_pad_left_luma(pu1_curr_pic_luma, i4_luma_stride, ps_pad_buf->u4_height, PAD_LEFT * i4_element_size); ps_codec->pf_pad_left_chroma(pu1_curr_pic_chroma, i4_chroma_stride, ps_pad_buf->u4_height >> 1, PAD_LEFT * i4_element_size); /* Pad right */ ps_codec->pf_pad_right_luma(pu1_curr_pic_luma + ps_pad_buf->u4_width * i4_element_size, i4_luma_stride, ps_pad_buf->u4_height, PAD_RIGHT * i4_element_size); ps_codec->pf_pad_right_chroma(pu1_curr_pic_chroma + ps_pad_buf->u4_width * i4_element_size, i4_chroma_stride, ps_pad_buf->u4_height >> 1, PAD_RIGHT * i4_element_size); /* Pad top */ ps_codec->pf_pad_top(pu1_curr_pic_luma - (PAD_LEFT * i4_element_size), i4_luma_stride, (ps_pad_buf->u4_width + PAD_WD) * i4_element_size, PAD_TOP); ps_codec->pf_pad_top(pu1_curr_pic_chroma - (PAD_LEFT * i4_element_size), i4_chroma_stride, (ps_pad_buf->u4_width + PAD_WD) * i4_element_size, PAD_TOP >> 1); /* Pad bottom */ ps_codec->pf_pad_bottom( pu1_curr_pic_luma + i4_bottom_offset_luma - (PAD_LEFT * i4_element_size), i4_luma_stride, (ps_pad_buf->u4_width + PAD_WD) * i4_element_size, PAD_BOT); ps_codec->pf_pad_bottom( pu1_curr_pic_chroma + i4_bottom_offset_chroma - (PAD_LEFT * i4_element_size), i4_chroma_stride, (ps_pad_buf->u4_width + PAD_WD) * i4_element_size, PAD_BOT >> 1); return IH264E_SUCCESS; } void isvce_svc_pad_frame(isvce_process_ctxt_t *ps_proc) { isvce_codec_t *ps_codec = ps_proc->ps_codec; isvce_pad_frame(ps_proc, &(ps_proc->s_rec_pic_buf_props)); if(ps_proc->s_svc_params.u1_num_spatial_layers > 1) { isvce_pad_frame( ps_proc, &(ps_codec->s_svc_ilp_data.ps_intra_recon_bufs[ps_proc->u1_spatial_layer_id])); isvce_pad_frame(ps_proc, &(ps_codec->s_svc_ilp_data.ps_residual_bufs[ps_proc->u1_spatial_layer_id])); } } /** ******************************************************************************* * * @brief * Initialize AIR mb frame Map * * @par Description: * Initialize AIR mb frame map * MB frame map indicates which frame an Mb should be coded as intra according *to AIR * * @param[in] ps_codec * Pointer to codec context * * @returns error_status * * @remarks * * ******************************************************************************* */ IH264E_ERROR_T isvce_init_air_map(isvce_codec_t *ps_codec) { /* intra refresh map */ UWORD16 *pu2_intr_rfrsh_map = ps_codec->pu2_intr_rfrsh_map; /* air mode */ IVE_AIR_MODE_T air_mode = ps_codec->s_cfg.e_air_mode; /* refresh period */ UWORD32 air_period = ps_codec->s_cfg.u4_air_refresh_period; /* mb cnt */ UWORD32 u4_mb_cnt = ps_codec->s_cfg.i4_wd_mbs * ps_codec->s_cfg.i4_ht_mbs; /* temp var */ UWORD32 curr_mb, seed_rand = 1; switch(air_mode) { case IVE_AIR_MODE_CYCLIC: for(curr_mb = 0; curr_mb < u4_mb_cnt; curr_mb++) { pu2_intr_rfrsh_map[curr_mb] = curr_mb % air_period; } break; case IVE_AIR_MODE_RANDOM: for(curr_mb = 0; curr_mb < u4_mb_cnt; curr_mb++) { seed_rand = (seed_rand * 32719 + 3) % 32749; pu2_intr_rfrsh_map[curr_mb] = seed_rand % air_period; } break; default: break; } return IH264E_SUCCESS; } /** ****************************************************************************** * * @brief * derivation process for macroblock availability * * @par Description * Calculates the availability of the left, top, topright and topleft macroblocks. * * @param[in] ps_proc_ctxt * pointer to proc context (handle) * * @remarks Based on section 6.4.5 in H264 spec * * @return none * ****************************************************************************** */ void isvce_derive_nghbr_avbl_of_mbs(isvce_process_ctxt_t *ps_proc) { UWORD8 *pu1_slice_idx_curr = ps_proc->pu1_slice_idx; UWORD8 *pu1_slice_idx_b; UWORD8 *pu1_slice_idx_a; UWORD8 *pu1_slice_idx_c; UWORD8 *pu1_slice_idx_d; block_neighbors_t *ps_ngbr_avbl; WORD32 i4_mb_x, i4_mb_y; WORD32 i4_wd_mbs; i4_mb_x = ps_proc->i4_mb_x; i4_mb_y = ps_proc->i4_mb_y; i4_wd_mbs = ps_proc->i4_wd_mbs; pu1_slice_idx_curr += (i4_mb_y * i4_wd_mbs) + i4_mb_x; pu1_slice_idx_a = pu1_slice_idx_curr - 1; pu1_slice_idx_b = pu1_slice_idx_curr - i4_wd_mbs; pu1_slice_idx_c = pu1_slice_idx_b + 1; pu1_slice_idx_d = pu1_slice_idx_b - 1; ps_ngbr_avbl = ps_proc->ps_ngbr_avbl; /**********************************************************************/ /* The macroblock is marked as available, unless one of the following */ /* conditions is true in which case the macroblock shall be marked as */ /* not available. */ /* 1. mbAddr < 0 */ /* 2 mbAddr > CurrMbAddr */ /* 3. the macroblock with address mbAddr belongs to a different slice */ /* than the macroblock with address CurrMbAddr */ /**********************************************************************/ /* left macroblock availability */ if(i4_mb_x == 0) { /* macroblocks along first column */ ps_ngbr_avbl->u1_mb_a = 0; } else { /* macroblocks belong to same slice? */ if(*pu1_slice_idx_a != *pu1_slice_idx_curr) ps_ngbr_avbl->u1_mb_a = 0; else ps_ngbr_avbl->u1_mb_a = 1; } /* top macroblock availability */ if(i4_mb_y == 0) { /* macroblocks along first row */ ps_ngbr_avbl->u1_mb_b = 0; } else { /* macroblocks belong to same slice? */ if(*pu1_slice_idx_b != *pu1_slice_idx_curr) ps_ngbr_avbl->u1_mb_b = 0; else ps_ngbr_avbl->u1_mb_b = 1; } /* top right macroblock availability */ if(i4_mb_x == i4_wd_mbs - 1 || i4_mb_y == 0) { /* macroblocks along last column */ ps_ngbr_avbl->u1_mb_c = 0; } else { /* macroblocks belong to same slice? */ if(*pu1_slice_idx_c != *pu1_slice_idx_curr) ps_ngbr_avbl->u1_mb_c = 0; else ps_ngbr_avbl->u1_mb_c = 1; } /* top left macroblock availability */ if(i4_mb_x == 0 || i4_mb_y == 0) { /* macroblocks along first column */ ps_ngbr_avbl->u1_mb_d = 0; } else { /* macroblocks belong to same slice? */ if(*pu1_slice_idx_d != *pu1_slice_idx_curr) ps_ngbr_avbl->u1_mb_d = 0; else ps_ngbr_avbl->u1_mb_d = 1; } } static IH264E_ERROR_T isvce_rc_init_wrapper(isvce_codec_t *ps_codec) { WORD32 i; isvce_cfg_params_t *ps_cfg = &ps_codec->s_cfg; IH264E_ERROR_T err = isvce_svc_rc_params_validate(ps_cfg); if(IH264E_SUCCESS != err) { return err; } for(i = 0; i < ps_cfg->s_svc_params.u1_num_spatial_layers; i++) { UWORD8 au1_init_qp[MAX_PIC_TYPE]; UWORD8 au1_min_max_qp[2 * MAX_PIC_TYPE]; au1_init_qp[0] = gau1_h264_to_mpeg2_qmap[ps_cfg->au4_i_qp[i]]; au1_init_qp[1] = gau1_h264_to_mpeg2_qmap[ps_cfg->au4_p_qp[i]]; au1_init_qp[2] = gau1_h264_to_mpeg2_qmap[ps_cfg->au4_b_qp[i]]; au1_min_max_qp[2 * I_PIC] = gau1_h264_to_mpeg2_qmap[ps_cfg->au4_i_qp_min[i]]; au1_min_max_qp[2 * I_PIC + 1] = gau1_h264_to_mpeg2_qmap[ps_cfg->au4_i_qp_max[i]]; au1_min_max_qp[2 * P_PIC] = gau1_h264_to_mpeg2_qmap[ps_cfg->au4_p_qp_min[i]]; au1_min_max_qp[2 * P_PIC + 1] = gau1_h264_to_mpeg2_qmap[ps_cfg->au4_p_qp_max[i]]; au1_min_max_qp[2 * B_PIC] = gau1_h264_to_mpeg2_qmap[ps_cfg->au4_b_qp_min[i]]; au1_min_max_qp[2 * B_PIC + 1] = gau1_h264_to_mpeg2_qmap[ps_cfg->au4_b_qp_max[i]]; switch(ps_cfg->e_rc_mode) { case IVE_RC_STORAGE: { ps_codec->s_rate_control.e_rc_type = VBR_STORAGE; break; } case IVE_RC_CBR_NON_LOW_DELAY: { ps_codec->s_rate_control.e_rc_type = CBR_NLDRC; break; } case IVE_RC_CBR_LOW_DELAY: { ps_codec->s_rate_control.e_rc_type = CBR_LDRC; break; } case IVE_RC_NONE: { ps_codec->s_rate_control.e_rc_type = CONST_QP; break; } default: { break; } } for(i = 0; i < MAX_NUM_SPATIAL_LAYERS; i++) { isvce_rc_init(ps_codec->s_rate_control.apps_rate_control_api[i], ps_codec->s_rate_control.pps_frame_time, ps_codec->s_rate_control.pps_time_stamp, ps_codec->s_rate_control.pps_pd_frm_rate, ps_cfg->u4_max_framerate, ps_cfg->u4_src_frame_rate, ps_cfg->u4_tgt_frame_rate, ps_codec->s_rate_control.e_rc_type, ps_cfg->au4_target_bitrate[i], ps_cfg->au4_max_bitrate[i], ps_cfg->au4_vbv_buffer_delay[i], ps_cfg->u4_i_frm_interval, ps_cfg->u4_num_bframes + 1, au1_init_qp, ps_cfg->u4_num_bframes + 2, au1_min_max_qp, ps_cfg->u4_max_level); } } return IH264E_SUCCESS; } /** ******************************************************************************* * * @brief * Codec level initializations * * @par Description: * Initializes the codec with parameters that needs to be set before encoding * first frame * * @param[in] ps_codec * Pointer to codec context * * @param[in] ps_inp_buf * Pointer to input buffer context * * @returns error_status * * @remarks * * ******************************************************************************* */ IH264E_ERROR_T isvce_codec_init(isvce_codec_t *ps_codec) { isa_dependent_fxns_t *ps_isa_dependent_fxns = &ps_codec->s_isa_dependent_fxns; enc_loop_fxns_t *ps_enc_loop_fxns = &ps_isa_dependent_fxns->s_enc_loop_fxns; WORD8 i; /******************************************************************** * INITIALIZE CODEC CONTEXT * ********************************************************************/ /* encoder presets */ if(ps_codec->s_cfg.u4_enc_speed_preset != IVE_CONFIG) { if(ps_codec->s_cfg.u4_enc_speed_preset == IVE_SLOWEST) { /* high quality */ /* enable diamond search */ ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH; ps_codec->s_cfg.u4_enable_fast_sad = 0; /* disable intra 4x4 */ ps_codec->s_cfg.u4_enable_intra_4x4 = 1; if(!FORCE_FAST_INTRA4X4) { ps_enc_loop_fxns->apf_luma_energy_compaction[1] = isvce_code_luma_intra_macroblock_4x4_rdopt_on; } /* sub pel off */ ps_codec->s_cfg.u4_enable_hpel = 1; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 0; } else if(ps_codec->s_cfg.u4_enc_speed_preset == IVE_NORMAL) { /* normal */ /* enable diamond search */ ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH; ps_codec->s_cfg.u4_enable_fast_sad = 0; /* disable intra 4x4 */ ps_codec->s_cfg.u4_enable_intra_4x4 = 1; /* sub pel off */ ps_codec->s_cfg.u4_enable_hpel = 1; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 0; } else if(ps_codec->s_cfg.u4_enc_speed_preset == IVE_FAST) { /* normal */ /* enable diamond search */ ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH; ps_codec->s_cfg.u4_enable_fast_sad = 0; /* disable intra 4x4 */ ps_codec->s_cfg.u4_enable_intra_4x4 = 0; /* sub pel off */ ps_codec->s_cfg.u4_enable_hpel = 1; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 1; } else if(ps_codec->s_cfg.u4_enc_speed_preset == IVE_HIGH_SPEED) { /* fast */ /* enable diamond search */ ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH; ps_codec->s_cfg.u4_enable_fast_sad = 0; /* disable intra 4x4 */ ps_codec->s_cfg.u4_enable_intra_4x4 = 0; /* sub pel off */ ps_codec->s_cfg.u4_enable_hpel = 0; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 0; } else if(ps_codec->s_cfg.u4_enc_speed_preset == IVE_FASTEST) { /* fastest */ /* enable diamond search */ ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH; /* disable intra 4x4 */ ps_codec->s_cfg.u4_enable_intra_4x4 = 0; /* sub pel off */ ps_codec->s_cfg.u4_enable_hpel = 0; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 1; } } /***************************************************************** * Initialize AIR inside codec *****************************************************************/ if(IVE_AIR_MODE_NONE != ps_codec->s_cfg.e_air_mode) { isvce_init_air_map(ps_codec); ps_codec->i4_air_pic_cnt = -1; } { WORD32 i4_err_code = isvce_rc_init_wrapper(ps_codec); if(IH264E_SUCCESS != i4_err_code) { return i4_err_code; } } /* recon stride */ ps_codec->i4_rec_strd = ALIGN16(ps_codec->s_cfg.u4_max_wd) + PAD_WD; /* max ref and reorder cnt */ ps_codec->i4_ref_buf_cnt = ps_codec->s_cfg.u4_max_ref_cnt + ps_codec->s_cfg.u4_max_reorder_cnt; ps_codec->i4_ref_buf_cnt += MAX_CTXT_SETS; ps_codec->i4_ref_buf_cnt += ps_codec->s_cfg.s_svc_params.u1_num_temporal_layers; DEBUG_HISTOGRAM_INIT(); /* Init dependecy vars */ ps_codec->i4_last_inp_buff_received = 0; /* At codec start no IDR is pending */ ps_codec->i4_pending_idr_flag = 0; for(i = 0; i < ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers - 1; i++) { ps_codec->au4_constrained_intra_pred[i] = 1; } ps_codec->au4_constrained_intra_pred[ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers - 1] = 0; return IH264E_SUCCESS; } /** ******************************************************************************* * * @brief update encoder configuration parameters * * @par Description: * updates encoder configuration parameters from the given config set. * Initialize/reinitialize codec parameters according to new configurations. * * @param[in] ps_codec * Pointer to codec context * * @param[in] ps_cfg * Pointer to config param set * * @remarks none * ******************************************************************************* */ IH264E_ERROR_T isvce_codec_update_config(isvce_codec_t *ps_codec, isvce_cfg_params_t *ps_cfg) { /* config params */ isvce_cfg_params_t *ps_curr_cfg = &ps_codec->s_cfg; /* error status */ IH264E_ERROR_T err = IH264E_SUCCESS; /* temp var */ UWORD32 u4_init_rc = 0; WORD8 i; /***********************/ /* UPDATE CODEC CONFIG */ /***********************/ if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_DIMENSIONS) { UWORD32 wd_aln = ALIGN16(ps_cfg->u4_wd); UWORD32 ht_aln = ALIGN16(ps_cfg->u4_ht); if(ps_curr_cfg->u4_wd != wd_aln || ps_curr_cfg->u4_ht != ht_aln || ps_curr_cfg->u4_disp_wd != ps_cfg->u4_disp_wd || ps_curr_cfg->u4_disp_ht != ps_cfg->u4_disp_ht) { ps_curr_cfg->u4_wd = wd_aln; ps_curr_cfg->u4_ht = ht_aln; ps_curr_cfg->u4_disp_wd = ps_cfg->u4_disp_wd; ps_curr_cfg->u4_disp_ht = ps_cfg->u4_disp_ht; ps_curr_cfg->i4_wd_mbs = ps_curr_cfg->u4_wd >> 4; ps_curr_cfg->i4_ht_mbs = ps_curr_cfg->u4_ht >> 4; ps_codec->i4_rec_strd = ALIGN16(ps_cfg->u4_wd) + PAD_WD; /* If number of MBs in a frame changes the air map also changes. * Hence recompute air map also reset air pic cnt */ if(ps_codec->s_cfg.e_air_mode != IVE_AIR_MODE_NONE) { /* re-init the air map */ isvce_init_air_map(ps_codec); /* reset air counter */ ps_codec->i4_air_pic_cnt = -1; } /* initialize mv bank buffer manager */ err = isvce_svc_au_data_mgr_add_bufs(ps_codec); if(err != IH264E_SUCCESS) return err; /* initialize ref bank buffer manager */ err = isvce_svc_au_buf_mgr_add_bufs(ps_codec); if(err != IH264E_SUCCESS) return err; /* since dimension changed, start new sequence by forcing IDR */ ps_codec->force_curr_frame_type = IV_IDR_FRAME; /* in case dimension changes, we need to reinitialize RC as the * old model shall not fit further */ u4_init_rc = 1; /* when the dimension changes, the header needs to be regenerated */ ps_codec->i4_gen_header = 1; } } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_FRAMERATE) { UWORD32 u4_src_ticks, u4_tgt_ticks; u4_src_ticks = ih264e_frame_time_get_src_ticks(ps_codec->s_rate_control.pps_frame_time); u4_tgt_ticks = ih264e_frame_time_get_tgt_ticks(ps_codec->s_rate_control.pps_frame_time); /* Change frame rate */ if(ps_codec->s_cfg.u4_src_frame_rate != ps_cfg->u4_src_frame_rate * 1000) { ps_codec->s_cfg.u4_src_frame_rate = ps_cfg->u4_src_frame_rate * 1000; ih264e_frame_time_update_src_frame_rate(ps_codec->s_rate_control.pps_frame_time, ps_codec->s_cfg.u4_src_frame_rate); ih264_time_stamp_update_frame_rate(ps_codec->s_rate_control.pps_time_stamp, ps_codec->s_cfg.u4_src_frame_rate); for(i = 0; i < ps_cfg->s_svc_params.u1_num_spatial_layers; i++) { irc_change_frame_rate(ps_codec->s_rate_control.apps_rate_control_api[i], ps_codec->s_cfg.u4_src_frame_rate, u4_src_ticks, u4_tgt_ticks); } } if(ps_codec->s_cfg.u4_tgt_frame_rate != ps_cfg->u4_tgt_frame_rate * 1000) { ps_codec->s_cfg.u4_tgt_frame_rate = ps_cfg->u4_tgt_frame_rate * 1000; ih264e_frame_time_update_tgt_frame_rate(ps_codec->s_rate_control.pps_frame_time, ps_codec->s_cfg.u4_tgt_frame_rate); for(i = 0; i < ps_cfg->s_svc_params.u1_num_spatial_layers; i++) { irc_change_frame_rate(ps_codec->s_rate_control.apps_rate_control_api[i], ps_codec->s_cfg.u4_src_frame_rate, u4_src_ticks, u4_tgt_ticks); irc_change_frm_rate_for_bit_alloc(ps_codec->s_rate_control.apps_rate_control_api[i], ps_codec->s_cfg.u4_tgt_frame_rate); } } } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_BITRATE) { for(i = 0; i < MAX_NUM_SPATIAL_LAYERS; i++) { if(ps_curr_cfg->au4_target_bitrate[i] != ps_cfg->au4_target_bitrate[i]) { if(IVE_RC_NONE != ps_curr_cfg->e_rc_mode) irc_change_avg_bit_rate(ps_codec->s_rate_control.apps_rate_control_api[i], ps_cfg->au4_target_bitrate[i]); ps_curr_cfg->au4_target_bitrate[i] = ps_cfg->au4_target_bitrate[i]; } } } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_FRAMETYPE) { switch(ps_cfg->e_frame_type) { case IV_I_FRAME: ps_codec->force_curr_frame_type = IV_I_FRAME; break; case IV_IDR_FRAME: ps_codec->force_curr_frame_type = IV_IDR_FRAME; break; case IV_P_FRAME: default: break; } } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_ME_PARAMS) { if(ps_curr_cfg->u4_enc_speed_preset == IVE_CONFIG) { ps_codec->s_cfg.u4_enable_hpel = ps_cfg->u4_enable_hpel; ps_codec->s_cfg.u4_enable_fast_sad = ps_cfg->u4_enable_fast_sad; ps_codec->s_cfg.u4_me_speed_preset = ps_cfg->u4_me_speed_preset; ps_codec->s_cfg.u4_enable_qpel = ps_cfg->u4_enable_qpel; } else if(ps_curr_cfg->u4_enc_speed_preset == IVE_FASTEST) { ps_codec->s_cfg.u4_enable_fast_sad = ps_cfg->u4_enable_fast_sad; } ps_codec->s_cfg.u4_srch_rng_x = ps_cfg->u4_srch_rng_x; ps_codec->s_cfg.u4_srch_rng_y = ps_cfg->u4_srch_rng_y; if(ps_codec->s_cfg.u4_enable_alt_ref != ps_cfg->u4_enable_alt_ref) { ps_codec->s_cfg.u4_enable_alt_ref = ps_cfg->u4_enable_alt_ref; ps_codec->u4_is_curr_frm_ref = 1; } } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_IPE_PARAMS) { ps_curr_cfg->u4_enc_speed_preset = ps_cfg->u4_enc_speed_preset; if(ps_curr_cfg->u4_enc_speed_preset == IVE_SLOWEST) { isa_dependent_fxns_t *ps_isa_dependent_fxns = &ps_codec->s_isa_dependent_fxns; enc_loop_fxns_t *ps_enc_loop_fxns = &ps_isa_dependent_fxns->s_enc_loop_fxns; /* enable diamond search */ ps_curr_cfg->u4_me_speed_preset = DMND_SRCH; ps_curr_cfg->u4_enable_fast_sad = 0; /* disable intra 4x4 */ ps_curr_cfg->u4_enable_intra_4x4 = 1; ps_enc_loop_fxns->apf_luma_energy_compaction[1] = isvce_code_luma_intra_macroblock_4x4_rdopt_on; /* sub pel off */ ps_curr_cfg->u4_enable_hpel = 1; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 0; } else if(ps_curr_cfg->u4_enc_speed_preset == IVE_NORMAL) { /* normal */ /* enable diamond search */ ps_curr_cfg->u4_me_speed_preset = DMND_SRCH; ps_curr_cfg->u4_enable_fast_sad = 0; /* disable intra 4x4 */ ps_curr_cfg->u4_enable_intra_4x4 = 1; /* sub pel off */ ps_curr_cfg->u4_enable_hpel = 1; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 0; } else if(ps_curr_cfg->u4_enc_speed_preset == IVE_FAST) { /* normal */ /* enable diamond search */ ps_curr_cfg->u4_me_speed_preset = DMND_SRCH; ps_curr_cfg->u4_enable_fast_sad = 0; /* disable intra 4x4 */ ps_curr_cfg->u4_enable_intra_4x4 = 0; /* sub pel off */ ps_curr_cfg->u4_enable_hpel = 1; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 1; } else if(ps_curr_cfg->u4_enc_speed_preset == IVE_HIGH_SPEED) { /* fast */ /* enable diamond search */ ps_curr_cfg->u4_me_speed_preset = DMND_SRCH; ps_curr_cfg->u4_enable_fast_sad = 0; /* disable intra 4x4 */ ps_curr_cfg->u4_enable_intra_4x4 = 0; /* sub pel off */ ps_curr_cfg->u4_enable_hpel = 0; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 0; } else if(ps_curr_cfg->u4_enc_speed_preset == IVE_FASTEST) { /* fastest */ /* enable diamond search */ ps_curr_cfg->u4_me_speed_preset = DMND_SRCH; // u4_num_layers = 4; /* disable intra 4x4 */ ps_curr_cfg->u4_enable_intra_4x4 = 0; /* sub pel off */ ps_curr_cfg->u4_enable_hpel = 0; /* disabled intra inter gating in Inter slices */ ps_codec->u4_inter_gate = 1; } else if(ps_curr_cfg->u4_enc_speed_preset == IVE_CONFIG) { ps_curr_cfg->u4_enable_intra_4x4 = ps_cfg->u4_enable_intra_4x4; } } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_GOP_PARAMS) { if(ps_curr_cfg->u4_i_frm_interval != ps_cfg->u4_i_frm_interval) { ps_curr_cfg->u4_i_frm_interval = ps_cfg->u4_i_frm_interval; /* reset air counter */ ps_codec->i4_air_pic_cnt = -1; /* re-init air map */ isvce_init_air_map(ps_codec); /*Effect intra frame interval change*/ for(i = 0; i < ps_cfg->s_svc_params.u1_num_spatial_layers; i++) { irc_change_intra_frm_int_call(ps_codec->s_rate_control.apps_rate_control_api[i], ps_curr_cfg->u4_i_frm_interval); } } ps_curr_cfg->u4_idr_frm_interval = ps_cfg->u4_idr_frm_interval; } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_DEBLOCK_PARAMS) { ps_curr_cfg->u4_disable_deblock_level = ps_cfg->u4_disable_deblock_level; } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_QP) { for(i = 0; i < ps_cfg->s_svc_params.u1_num_spatial_layers; i++) { UWORD8 au1_init_qp[MAX_PIC_TYPE]; UWORD8 au1_min_max_qp[2 * MAX_PIC_TYPE]; UWORD8 au1_min_max_avc_qp[2 * MAX_PIC_TYPE]; ps_codec->s_cfg.au4_i_qp_max[i] = ps_cfg->au4_i_qp_max[i]; ps_codec->s_cfg.au4_i_qp_min[i] = ps_cfg->au4_i_qp_min[i]; ps_codec->s_cfg.au4_i_qp[i] = ps_cfg->au4_i_qp[i]; ps_codec->s_cfg.au4_p_qp_max[i] = ps_cfg->au4_p_qp_max[i]; ps_codec->s_cfg.au4_p_qp_min[i] = ps_cfg->au4_p_qp_min[i]; ps_codec->s_cfg.au4_p_qp[i] = ps_cfg->au4_p_qp[i]; ps_codec->s_cfg.au4_b_qp_max[i] = ps_cfg->au4_b_qp_max[i]; ps_codec->s_cfg.au4_b_qp_min[i] = ps_cfg->au4_b_qp_min[i]; ps_codec->s_cfg.au4_b_qp[i] = ps_cfg->au4_b_qp[i]; /* update rc lib with modified qp */ au1_init_qp[0] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.au4_i_qp[i]]; au1_init_qp[1] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.au4_p_qp[i]]; au1_init_qp[2] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.au4_b_qp[i]]; irc_change_init_qp(ps_codec->s_rate_control.apps_rate_control_api[i], au1_init_qp); au1_min_max_qp[2 * I_PIC] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.au4_i_qp_min[i]]; au1_min_max_qp[2 * I_PIC + 1] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.au4_i_qp_max[i]]; au1_min_max_qp[2 * P_PIC] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.au4_p_qp_min[i]]; au1_min_max_qp[2 * P_PIC + 1] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.au4_p_qp_max[i]]; au1_min_max_qp[2 * B_PIC] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.au4_b_qp_min[i]]; au1_min_max_qp[2 * B_PIC + 1] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.au4_b_qp_max[i]]; au1_min_max_avc_qp[2 * I_PIC] = ps_codec->s_cfg.au4_i_qp_min[i]; au1_min_max_avc_qp[2 * I_PIC + 1] = ps_codec->s_cfg.au4_i_qp_max[i]; au1_min_max_avc_qp[2 * P_PIC] = ps_codec->s_cfg.au4_p_qp_min[i]; au1_min_max_avc_qp[2 * P_PIC + 1] = ps_codec->s_cfg.au4_p_qp_max[i]; au1_min_max_avc_qp[2 * B_PIC] = ps_codec->s_cfg.au4_b_qp_min[i]; au1_min_max_avc_qp[2 * B_PIC + 1] = ps_codec->s_cfg.au4_b_qp_max[i]; irc_change_qp_constraints(ps_codec->s_rate_control.apps_rate_control_api[i], au1_min_max_qp, au1_min_max_avc_qp); } } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_ENC_MODE) { ps_codec->s_cfg.e_enc_mode = ps_cfg->e_enc_mode; if(ps_codec->s_cfg.e_enc_mode == IVE_ENC_MODE_HEADER) { ps_codec->i4_header_mode = 1; ps_codec->s_cfg.e_enc_mode = IVE_ENC_MODE_PICTURE; } else { ps_codec->i4_header_mode = 0; } } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_VBV_PARAMS && IVE_RC_NONE != ps_codec->s_cfg.e_rc_mode) { for(i = 0; i < ps_cfg->s_svc_params.u1_num_spatial_layers; i++) { ps_codec->s_cfg.au4_vbv_buffer_delay[i] = ps_cfg->au4_vbv_buffer_delay[i]; } // irc_change_buffer_delay(ps_codec->s_rate_control.pps_rate_control_api, // ps_codec->s_cfg.u4_vbv_buffer_delay); // TODO: remove this when the support for changing buffer dynamically // is yet to be added. u4_init_rc = 1; } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_AIR_PARAMS) { if(ps_curr_cfg->e_air_mode != ps_cfg->e_air_mode || ps_curr_cfg->u4_air_refresh_period != ps_cfg->u4_air_refresh_period) { ps_curr_cfg->e_air_mode = ps_cfg->e_air_mode; ps_curr_cfg->u4_air_refresh_period = ps_cfg->u4_air_refresh_period; isvce_init_air_map(ps_codec); /* reset air counter */ ps_codec->i4_air_pic_cnt = -1; } } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_PROFILE_PARAMS) { ps_codec->s_cfg.e_profile = ps_cfg->e_profile; ps_codec->s_cfg.u4_entropy_coding_mode = ps_cfg->u4_entropy_coding_mode; } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_NUM_CORES) { ps_codec->s_cfg.u4_num_cores = ps_cfg->u4_num_cores; } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_VUI_PARAMS) { ps_codec->s_cfg.s_vui = ps_cfg->s_vui; } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_SEI_MDCV_PARAMS) { ps_codec->s_cfg.s_sei.u1_sei_mdcv_params_present_flag = ps_cfg->s_sei.u1_sei_mdcv_params_present_flag; ps_codec->s_cfg.s_sei.s_sei_mdcv_params = ps_cfg->s_sei.s_sei_mdcv_params; } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_SEI_CLL_PARAMS) { ps_codec->s_cfg.s_sei.u1_sei_cll_params_present_flag = ps_cfg->s_sei.u1_sei_cll_params_present_flag; ps_codec->s_cfg.s_sei.s_sei_cll_params = ps_cfg->s_sei.s_sei_cll_params; } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_SEI_AVE_PARAMS) { ps_codec->s_cfg.s_sei.u1_sei_ave_params_present_flag = ps_cfg->s_sei.u1_sei_ave_params_present_flag; ps_codec->s_cfg.s_sei.s_sei_ave_params = ps_cfg->s_sei.s_sei_ave_params; } else if(ps_cfg->e_cmd == ISVCE_CMD_CTL_SET_SEI_CCV_PARAMS) { ps_codec->s_cfg.s_sei.u1_sei_ccv_params_present_flag = ps_cfg->s_sei.u1_sei_ccv_params_present_flag; ps_codec->s_cfg.s_sei.s_sei_ccv_params = ps_cfg->s_sei.s_sei_ccv_params; } /* reset RC model */ if(u4_init_rc) { err = isvce_rc_init_wrapper(ps_codec); } return err; } static FORCEINLINE void isvce_change_rc_init_qp(void *pv_rate_control_api, UWORD8 u1_qp) { UWORD8 au1_pic_qps[MAX_PIC_TYPE]; WORD32 i; for(i = 0; i < MAX_PIC_TYPE; i++) { au1_pic_qps[i] = gau1_h264_to_mpeg2_qmap[CLIP3(MIN_H264_QP, MAX_H264_QP, u1_qp + i)]; } irc_change_init_qp(pv_rate_control_api, au1_pic_qps); } /** ******************************************************************************* * * @brief * Queues the current buffer, gets back a another buffer for encoding with *corrent picture type * * @par Description: * This function performs 3 distinct but related functions. * 1) Maintains an input queue [Note the the term queue donot imply a * first-in first-out logic here] that queues input and dequeues them so * that input frames can be encoded at any predetermined encoding order * 2) Uses RC library to decide which frame must be encoded in current pass * and which picture type it must be encoded to. * 3) Uses RC library to decide the QP at which current frame has to be * encoded * 4) Determines if the current picture must be encoded or not based on * PRE-ENC skip * * Input queue is used for storing input buffers till they are used for * encoding. This queue is maintained at ps_codec->as_inp_list. Whenever a * valid input comes, it is added to the end of queue. This same input is * added to RC queue using the identifier as ps_codec->i4_pic_cnt. Hence any * pic from RC can be located in the input queue easily. * * The dequeue operation does not start till we have *ps_codec->s_cfg.u4_max_num_bframes frames in the queue. THis is done in order *to ensure that once output starts we will have a constant stream of output *with no gaps. * * THe output frame order is governed by RC library. When ever we dequeue a * buffer from RC library, it ensures that we will get them in encoding *order With the output of RC library, we can use the picture id to dequeue the * corresponding buffer from input queue and encode it. * * Condition at the end of stream. * ------------------------------- * At the last valid buffer from the app, we will get ps_ive_ip->u4_is_last * to be set. This will the given to lib when appropriate input buffer is * given to encoding. * * Since we have to output is not in sync with input, we will have frames *to encode even after we recive the last vaild input buffer. Hence we have to * make sure that we donot queue any new buffers once we get the flag [It *may mess up GOP ?]. This is acheived by setting *ps_codec->i4_last_inp_buff_received to act as a permenent marker for last *frame recived [This may not be needed, because in our current app, all buffers *after the last are marked as last. But can we rely on that?] . Hence after *this flgag is set no new buffers are queued. * * @param[in] ps_codec * Pointer to codec descriptor * * @param[in] ps_ive_ip * Current input buffer to the encoder * * @param[out] ps_inp * Buffer to be encoded in the current pass * * @returns * Flag indicating if we have a pre-enc skip or not * * @remarks * TODO (bpic) * The check for null ans is last is redudent. * Need to see if we can remove it * ******************************************************************************* */ WORD32 isvce_input_queue_update(isvce_codec_t *ps_codec, ive_video_encode_ip_t *ps_ive_ip, isvce_inp_buf_t *ps_enc_buff, WORD8 i1_layer_id) { isvce_inp_buf_t *ps_inp_buf; picture_type_e e_pictype; WORD32 i4_skip; UWORD32 ctxt_sel, u4_pic_id, u4_pic_disp_id; UWORD8 u1_frame_qp = MAX_H264_QP; UWORD32 max_frame_bits = 0x7FFFFFFF; WORD32 i; /* Mark that the last input frame has been received */ if(ps_ive_ip->u4_is_last == 1) { ps_codec->i4_last_inp_buff_received = 1; } if(ps_ive_ip->s_inp_buf.apv_bufs[0] == NULL && !ps_codec->i4_last_inp_buff_received) { ps_enc_buff->s_inp_props.s_raw_buf.apv_bufs[0] = NULL; ps_enc_buff->s_inp_props.u4_is_last = ps_ive_ip->u4_is_last; return 0; } /*************************************************************************** * Check for pre enc skip * When src and target frame rates donot match, we skip some frames to * maintain the relation ship between them **************************************************************************/ { WORD32 skip_src; skip_src = isvce_update_rc_framerates( ps_codec->s_rate_control.apps_rate_control_api[i1_layer_id], ps_codec->s_rate_control.pps_pd_frm_rate, ps_codec->s_rate_control.pps_time_stamp, ps_codec->s_rate_control.pps_frame_time); if(skip_src) { ps_enc_buff->s_inp_props.u4_is_last = ps_ive_ip->u4_is_last; return 1; } } /*************************************************************************** *Queue the input to the queue **************************************************************************/ ps_inp_buf = &(ps_codec->as_inp_list[ps_codec->i4_pic_cnt % SVC_MAX_NUM_INP_FRAMES]); /* copy input info. to internal structure */ ps_inp_buf->s_inp_props.s_raw_buf = ps_ive_ip->s_inp_buf; ps_inp_buf->s_inp_props.u4_timestamp_low = ps_ive_ip->u4_timestamp_low; ps_inp_buf->s_inp_props.u4_timestamp_high = ps_ive_ip->u4_timestamp_high; ps_inp_buf->s_inp_props.u4_is_last = ps_ive_ip->u4_is_last; ps_inp_buf->s_inp_props.pv_mb_info = ps_ive_ip->pv_mb_info; ps_inp_buf->s_inp_props.u4_mb_info_type = ps_ive_ip->u4_mb_info_type; ps_inp_buf->s_inp_props.pv_pic_info = ps_ive_ip->pv_pic_info; ps_inp_buf->s_inp_props.u4_pic_info_type = ps_ive_ip->u4_pic_info_type; ps_inp_buf->s_inp_props.u1_sei_ccv_params_present_flag = ps_codec->s_cfg.s_sei.u1_sei_ccv_params_present_flag; ps_inp_buf->s_inp_props.s_sei_ccv = ps_codec->s_cfg.s_sei.s_sei_ccv_params; if(ps_inp_buf->s_inp_props.s_raw_buf.apv_bufs[0]) isvce_svc_inp_buf_populate(ps_codec, ps_inp_buf); /*************************************************************************** * Now we should add the picture to RC stack here **************************************************************************/ /* * If an I frame has been requested, ask RC to force it * For IDR requests, we have to ask RC to force I and set IDR by our selves * since RC Donot know about IDR. For forcing an IDR at dequeue stage we * should record that an IDR has been requested some where. Hence we will * store it in the u4_idr_inp_list at a position same as that of input frame */ { WORD32 i4_force_idr, i4_force_i; i4_force_idr = (ps_codec->force_curr_frame_type == IV_IDR_FRAME); i4_force_idr |= !(ps_codec->i4_pic_cnt % ps_codec->s_cfg.u4_idr_frm_interval); i4_force_i = (ps_codec->force_curr_frame_type == IV_I_FRAME); ps_codec->i4_pending_idr_flag |= i4_force_idr; if((ps_codec->i4_pic_cnt > 0) && (i4_force_idr || i4_force_i)) { irc_force_I_frame(ps_codec->s_rate_control.apps_rate_control_api[i1_layer_id]); } if(i1_layer_id == (ps_codec->s_cfg.s_svc_params.u1_num_spatial_layers - 1)) { ps_codec->force_curr_frame_type = IV_NA_FRAME; } } irc_add_picture_to_stack(ps_codec->s_rate_control.apps_rate_control_api[i1_layer_id], ps_codec->i4_pic_cnt); /* Delay */ if(ps_codec->i4_encode_api_call_cnt < (WORD32) (ps_codec->s_cfg.u4_num_bframes)) { ps_enc_buff->s_inp_props.s_raw_buf.apv_bufs[0] = NULL; ps_enc_buff->s_inp_props.u4_is_last = 0; return 0; } /*************************************************************************** * Get a new pic to encode **************************************************************************/ /* Query the picture_type */ e_pictype = isvce_rc_get_picture_details(ps_codec->s_rate_control.apps_rate_control_api[i1_layer_id], (WORD32 *) (&u4_pic_id), (WORD32 *) (&u4_pic_disp_id)); switch(e_pictype) { case I_PIC: ps_codec->pic_type = PIC_I; break; case P_PIC: ps_codec->pic_type = PIC_P; break; case B_PIC: ps_codec->pic_type = PIC_B; break; default: ps_codec->pic_type = PIC_NA; ps_enc_buff->s_inp_props.s_raw_buf.apv_bufs[0] = NULL; return 0; } /* Set IDR if it has been requested */ if(ps_codec->pic_type == PIC_I) { ps_codec->pic_type = ps_codec->i4_pending_idr_flag ? PIC_IDR : ps_codec->pic_type; ps_codec->i4_pending_idr_flag = 0; } if(ps_codec->s_rate_control.e_rc_type != CONST_QP && ps_codec->u1_enable_init_qp && (u4_pic_id == 0 || irc_is_scenecut(ps_codec->s_rate_control.apps_rate_control_api[i1_layer_id]))) { DOUBLE d_bpp; svc_rc_utils_ctxt_t *ps_svc_rc_utils = &ps_codec->s_rate_control.s_rc_utils; UWORD32 u4_src_fps = ps_codec->s_cfg.u4_src_frame_rate / 1000; UWORD32 u4_wd = ps_inp_buf->as_layer_yuv_buf_props[i1_layer_id].u4_width; UWORD32 u4_ht = ps_inp_buf->as_layer_yuv_buf_props[i1_layer_id].u4_height; DOUBLE d_gpp = isvce_compute_gpp(ps_svc_rc_utils, &ps_inp_buf->as_layer_yuv_buf_props[i1_layer_id]); d_bpp = ((DOUBLE) irc_get_vbv_buf_size( ps_codec->s_rate_control.apps_rate_control_api[i1_layer_id]) / 10.) / ((DOUBLE) (u4_src_fps * u4_wd * u4_ht)); u1_frame_qp = (UWORD8) irc_get_frame_level_init_qp( ps_codec->s_rate_control.apps_rate_control_api[i1_layer_id], ps_codec->s_rate_control.e_rc_type, e_pictype, d_bpp, d_gpp); isvce_change_rc_init_qp(ps_codec->s_rate_control.apps_rate_control_api[i1_layer_id], u1_frame_qp); ps_codec->au4_frame_qp[i1_layer_id] = u1_frame_qp; } else { /* Get current frame Qp */ u1_frame_qp = (UWORD8) irc_get_frame_level_qp( ps_codec->s_rate_control.apps_rate_control_api[i1_layer_id], e_pictype, max_frame_bits); ps_codec->au4_frame_qp[i1_layer_id] = gau1_mpeg2_to_h264_qmap[u1_frame_qp]; } /* * copy the pic id to poc because the display order is assumed to be same * as input order */ ps_codec->i4_poc = u4_pic_id; /*************************************************************************** * Now retrieve the correct picture from the queue **************************************************************************/ /* Mark the skip flag */ i4_skip = 0; ctxt_sel = ps_codec->i4_encode_api_call_cnt % MAX_CTXT_SETS; ps_codec->s_rate_control.pre_encode_skip[ctxt_sel] = i4_skip; /* Get a buffer to encode */ ps_inp_buf = &(ps_codec->as_inp_list[u4_pic_id % SVC_MAX_NUM_INP_FRAMES]); /* copy dequeued input to output */ ps_enc_buff[0] = ps_inp_buf[0]; /* Special case for encoding trailing B frames * * In encoding streams with B frames it may happen that we have a B frame * at the end without a P/I frame after it. Hence when we are dequeing from * the RC, it will return the P frame [next in display order but before in * encoding order] first. Since the dequeue happens for an invalid frame we * will get a frame with null buff and set u4_is_last. Hence lib with return * last frame flag at this point and will stop encoding. * * Since for the last B frame, we does not have the forward ref frame * it makes sense to force it into P. * * To solve this, in case the current frame is P and if the last frame flag * is set, we need to see if there is and pending B frames. If there are any, * we should just encode that picture as the current P frame and set * that B frame as the last frame. Hence the encoder will terminate naturally * once that B-frame is encoded after all the in between frames. * * Since we cannot touch RC stack directly, the option of actually swapping * frames in RC is ruled out. We have to modify the as_inp_list to simulate * such a behavior by RC. We can do that by * 1) Search through as_inp_list to locate the largest u4_timestamp_low less * than current u4_timestamp_low. This will give us the last B frame * before the current P frame. Note that this will handle pre encode skip too * since queue happens after pre enc skip. 2) Swap the position in * as_inp_list. Hence now the last B frame is encoded as P frame. And the new * last B frame will have u4_is_last set so that encoder will end naturally * once we reached that B frame or any subsequent frame. Also the current GOP * will have 1 less B frame Since we are swapping, the poc will also be * in-order. 3) In case we have an IPP stream, the result of our search will * be an I/P frame which is already encoded. Thus swap and encode will result * in encoding of duplicate frames. Hence to avoid this we will only * have this work around in case of u4_num_bframes > 0. * * In case we have forced an I/IDR frame In between this P frame and * the last B frame -> This cannot happen as the current P frame is * supposed to have u4_is_last set. Thus forcing an I/ IDR after this * is illogical. * * In cae if we have forced an I such that the frame just before last * frame in is I/P -> This case will never arise. Since we have a closed GOP * now, once we force an I, the gop gets reset, hence there will be a B * between I/P and I/P. */ if(ps_enc_buff->s_inp_props.u4_is_last && (ps_codec->pic_type == PIC_P) && ps_codec->s_cfg.u4_num_bframes) { WORD32 cntr; WORD32 lst_bframe = -1; UWORD32 u4_timestamp_low = 0; UWORD32 u4_timestamp_high = 0; isvce_inp_buf_t *ps_swap_buff, *ps_inp_list; ps_inp_list = &ps_codec->as_inp_list[0]; /* Now search the inp list for highest timestamp */ for(cntr = 0; cntr < SVC_MAX_NUM_INP_FRAMES; cntr++) { if(ps_inp_list[cntr].s_inp_props.s_raw_buf.apv_bufs[0] != NULL) { if((ps_inp_list[cntr].s_inp_props.u4_timestamp_high > u4_timestamp_high) || (ps_inp_list[cntr].s_inp_props.u4_timestamp_high == u4_timestamp_high && ps_inp_list[cntr].s_inp_props.u4_timestamp_low > u4_timestamp_low)) { u4_timestamp_low = ps_inp_list[cntr].s_inp_props.u4_timestamp_low; u4_timestamp_high = ps_inp_list[cntr].s_inp_props.u4_timestamp_high; lst_bframe = cntr; } } } if(lst_bframe != -1) { ps_swap_buff = &(ps_codec->as_inp_list[lst_bframe]); /* copy the last B buffer to output */ *ps_enc_buff = *ps_swap_buff; /* Store the current buf into the queue in place of last B buf */ *ps_swap_buff = *ps_inp_buf; } } if(ps_enc_buff->s_inp_props.u4_is_last) { ps_codec->pic_type = PIC_NA; } /* The buffer in the queue is set to NULL to specify that encoding is done for * that frame */ for(i = 0; i < 3; i++) { ps_inp_buf->s_inp_props.s_raw_buf.apv_bufs[i] = NULL; } /* Return the buffer status */ return (0); } /** ****************************************************************************** * * @brief * This function joins all the spawned threads after successful completion of * their tasks * * @par Description * * @param[in] ps_codec * pointer to codec context * * @returns none * ****************************************************************************** */ void isvce_join_threads(isvce_codec_t *ps_codec) { WORD32 i = 0; WORD32 ret = 0; /* join spawned threads */ while(i < ps_codec->i4_proc_thread_cnt) { if(ps_codec->ai4_process_thread_created[i]) { ret = ithread_join(ps_codec->apv_proc_thread_handle[i], NULL); if(ret != 0) { ASSERT(0); } ps_codec->ai4_process_thread_created[i] = 0; i++; } } ps_codec->i4_proc_thread_cnt = 0; } UWORD32 isvce_get_min_outbuf_size(UWORD32 u4_wd, UWORD32 u4_ht, UWORD8 u1_num_spatial_layers) { return MAX((u4_wd * u4_ht * 3), MIN_STREAM_SIZE) * u1_num_spatial_layers; }