/****************************************************************************** * * Copyright (C) 2015 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 * ideint_api.c * * @brief * This file contains the definitions of the core processing of the de- * interlacer. * * @author * Ittiam * * @par List of Functions: * * @remarks * None * ******************************************************************************* */ /*****************************************************************************/ /* File Includes */ /*****************************************************************************/ /* System include files */ #include #include #include #include #include /* User include files */ #include "icv_datatypes.h" #include "icv_macros.h" #include "icv_platform_macros.h" #include "icv.h" #include "icv_variance.h" #include "icv_sad.h" #include "ideint.h" #include "ideint_defs.h" #include "ideint_structs.h" #include "ideint_utils.h" #include "ideint_cac.h" #include "ideint_debug.h" #include "ideint_function_selector.h" /** ******************************************************************************* * * @brief * Return deinterlacer context size * * @par Description * Return deinterlacer context size, application will allocate this memory * and send it as context to process call * * @param[in] None * * @returns * Size of deinterlacer context * * @remarks * None * ******************************************************************************* */ WORD32 ideint_ctxt_size(void) { return sizeof(ctxt_t); } /** ******************************************************************************* * * @brief * Deinterlace given fields and produce a frame * * @par Description * Deinterlacer function that deinterlaces given fields and produces a frame * * @param[in] pv_ctxt * Deinterlacer context returned by ideint_create() * * @param[in] ps_prv_fld * Previous field (can be null, in which case spatial filtering is done * unconditionally) * * @param[in] ps_cur_fld * Current field * * @param[in] ps_nxt_fld * Next field * * @param[in] ps_out_frm * Output frame * * @param[in] ps_params * Parameters * * @param[in] start_row * Start row * * @param[in] num_rows * Number of rows to be processed * * @returns * IDEINT_ERROR_T * * @remarks * ******************************************************************************* */ IDEINT_ERROR_T ideint_process(void *pv_ctxt, icv_pic_t *ps_prv_fld, icv_pic_t *ps_cur_fld, icv_pic_t *ps_nxt_fld, icv_pic_t *ps_out_frm, ideint_params_t *ps_params, WORD32 start_row, WORD32 num_rows) { ctxt_t *ps_ctxt; WORD32 num_blks_x, num_blks_y; WORD32 num_comp; WORD32 i, row, col; WORD32 rows_remaining; if(NULL == pv_ctxt) return IDEINT_INVALID_CTXT; ps_ctxt = (ctxt_t *)pv_ctxt; /* Copy the parameters */ if(ps_params) { ps_ctxt->s_params = *ps_params; } else { /* Use default params if ps_params is NULL */ ps_ctxt->s_params.i4_cur_fld_top = 1; ps_ctxt->s_params.e_mode = IDEINT_MODE_SPATIAL; ps_ctxt->s_params.e_arch = ideint_default_arch(); ps_ctxt->s_params.e_soc = ICV_SOC_GENERIC; ps_ctxt->s_params.i4_disable_weave = 0; ps_ctxt->s_params.pf_aligned_alloc = NULL; ps_ctxt->s_params.pf_aligned_free = NULL; } /* Start row has to be multiple of 8 */ if(start_row & 0x7) { return IDEINT_START_ROW_UNALIGNED; } /* Initialize variances */ ps_ctxt->ai4_vrnc_avg_fb[0] = VAR_AVG_LUMA; ps_ctxt->ai4_vrnc_avg_fb[1] = VAR_AVG_CHROMA; ps_ctxt->ai4_vrnc_avg_fb[2] = VAR_AVG_CHROMA; ideint_init_function_ptr(ps_ctxt); rows_remaining = ps_out_frm->ai4_ht[0] - start_row; num_rows = MIN(num_rows, rows_remaining); IDEINT_CORRUPT_PIC(ps_out_frm, 0xCD); //Weave two fields to get a frame if(IDEINT_MODE_WEAVE == ps_ctxt->s_params.e_mode) { if(0 == ps_ctxt->s_params.i4_disable_weave) { if(ps_ctxt->s_params.i4_cur_fld_top) ideint_weave_pic(ps_cur_fld, ps_nxt_fld, ps_out_frm, start_row, num_rows); else ideint_weave_pic(ps_nxt_fld, ps_cur_fld, ps_out_frm, start_row, num_rows); } return IDEINT_ERROR_NONE; } num_comp = 3; for(i = 0; i < num_comp; i++) { UWORD8 *pu1_prv = NULL, *pu1_out; UWORD8 *pu1_top, *pu1_bot, *pu1_dst; WORD32 cur_strd, out_strd, dst_strd; WORD32 st_thresh; WORD32 vrnc_avg_st; WORD32 disable_cac_sad; WORD32 comp_row_start, comp_row_end; num_blks_x = ALIGN8(ps_out_frm->ai4_wd[i]) >> 3; num_blks_y = ALIGN8(ps_out_frm->ai4_ht[i]) >> 3; comp_row_start = start_row; comp_row_end = comp_row_start + num_rows; if(i) { comp_row_start >>= 1; comp_row_end >>= 1; } comp_row_end = MIN(comp_row_end, ps_out_frm->ai4_ht[i]); comp_row_start = ALIGN8(comp_row_start) >> 3; comp_row_end = ALIGN8(comp_row_end) >> 3; st_thresh = ST_THRESH; vrnc_avg_st = VAR_AVG_LUMA; if(i) { st_thresh = ST_THRESH >> 1; vrnc_avg_st = VAR_AVG_CHROMA; } out_strd = ps_out_frm->ai4_strd[i]; if(ps_ctxt->s_params.i4_cur_fld_top) { cur_strd = ps_cur_fld->ai4_strd[i]; } else { cur_strd = ps_nxt_fld->ai4_strd[i]; } disable_cac_sad = 0; /* If previous field is not provided, then change to SPATIAL mode */ if(ps_prv_fld->apu1_buf[i] == NULL) { disable_cac_sad = 1; } for(row = comp_row_start; row < comp_row_end; row++) { pu1_out = ps_out_frm->apu1_buf[i]; pu1_out += (ps_out_frm->ai4_strd[i] * row << 3); if(0 == disable_cac_sad) { pu1_prv = ps_prv_fld->apu1_buf[i]; pu1_prv += (ps_prv_fld->ai4_strd[i] * row << 2); } if(ps_ctxt->s_params.i4_cur_fld_top) { pu1_top = ps_cur_fld->apu1_buf[i]; pu1_bot = ps_nxt_fld->apu1_buf[i]; } else { pu1_top = ps_nxt_fld->apu1_buf[i]; pu1_bot = ps_cur_fld->apu1_buf[i]; } pu1_top += (cur_strd * row << 2); pu1_bot += (cur_strd * row << 2); for(col = 0; col < num_blks_x; col++) { WORD32 cac, sad, vrnc; WORD32 th_num, th_den; UWORD8 au1_dst[BLK_WD * BLK_HT]; WORD32 blk_wd, blk_ht; WORD32 input_boundary; cac = 0; sad = 0; th_den = 0; th_num = st_thresh; vrnc = 0; disable_cac_sad = 0; /* If previous field is not provided, then change to SPATIAL mode */ if(ps_prv_fld->apu1_buf[i] == NULL) { disable_cac_sad = 1; } /* For boundary blocks when input dimensions are not multiple of 8, * then change to spatial mode */ input_boundary = 0; blk_wd = BLK_WD; blk_ht = BLK_HT; if((((num_blks_x - 1) == col) && (ps_out_frm->ai4_wd[i] & 0x7)) || (((num_blks_y - 1) == row) && (ps_out_frm->ai4_ht[i] & 0x7))) { disable_cac_sad = 1; input_boundary = 1; if(((num_blks_x - 1) == col) && (ps_out_frm->ai4_wd[i] & 0x7)) blk_wd = (ps_out_frm->ai4_wd[i] & 0x7); if(((num_blks_y - 1) == row) && (ps_out_frm->ai4_ht[i] & 0x7)) blk_ht = (ps_out_frm->ai4_ht[i] & 0x7); } if(0 == disable_cac_sad) { /* Compute SAD */ PROFILE_DISABLE_SAD sad = ps_ctxt->pf_sad_8x4(pu1_prv, pu1_bot, cur_strd, cur_strd, BLK_WD, BLK_HT >> 1); /* Compute Variance */ PROFILE_DISABLE_VARIANCE vrnc = ps_ctxt->pf_variance_8x4(pu1_top, cur_strd, BLK_WD, BLK_HT >> 1); th_num = st_thresh; th_num *= vrnc_avg_st + ((MOD_IDX_ST_NUM * vrnc) >> MOD_IDX_ST_SHIFT); th_den = vrnc + ((MOD_IDX_ST_NUM * vrnc_avg_st) >> MOD_IDX_ST_SHIFT); if((sad * th_den) <= th_num) { /* Calculate Combing Artifact if SAD test fails */ PROFILE_DISABLE_CAC cac = ps_ctxt->pf_cac_8x8(pu1_top, pu1_bot, cur_strd, cur_strd); } } pu1_dst = pu1_out; dst_strd = out_strd; /* In case boundary blocks are not complete (dimensions non-multiple of 8) * Use intermediate buffer as destination and copy required pixels to output * buffer later */ if(input_boundary) { pu1_dst = au1_dst; dst_strd = BLK_WD; ideint_weave_blk(pu1_top, pu1_bot, pu1_dst, dst_strd, cur_strd, blk_wd, blk_ht); } /* Weave the two fields unconditionally */ if(0 == ps_ctxt->s_params.i4_disable_weave) { ideint_weave_blk(pu1_top, pu1_bot, pu1_dst, dst_strd, cur_strd, blk_wd, blk_ht); } if(disable_cac_sad || cac || (sad * th_den > th_num)) { /* Pad the input fields in an intermediate buffer if required */ if((0 == row) || (0 == col) || ((num_blks_x - 1) == col) || ((num_blks_y - 1) == row)) { UWORD8 *pu1_dst_top; UWORD8 au1_pad[(BLK_HT + 4) * (BLK_WD + 4)]; ideint_pad_blk(pu1_top, pu1_bot, au1_pad, cur_strd, row, col, num_blks_y, num_blks_x, blk_wd, blk_ht); pu1_dst_top = au1_pad + 2 * (BLK_WD + 4) + 2; PROFILE_DISABLE_SPATIAL ps_ctxt->pf_spatial_filter(pu1_dst_top, pu1_dst + dst_strd, (BLK_WD + 4) * 2, dst_strd * 2); } else { PROFILE_DISABLE_SPATIAL ps_ctxt->pf_spatial_filter(pu1_top, pu1_dst + dst_strd, cur_strd, dst_strd * 2); } } /* copy required pixels to output buffer for boundary blocks * when dimensions are not multiple of 8 */ if(input_boundary) { WORD32 j; for(j = 0; j < blk_ht; j++) { memcpy(pu1_out + j * out_strd, au1_dst + j * BLK_WD, blk_wd); } } if(NULL != pu1_prv) { pu1_prv += 8; } pu1_top += 8; pu1_bot += 8; pu1_out += 8; } } } return IDEINT_ERROR_NONE; }