You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
419 lines
13 KiB
419 lines
13 KiB
/****************************************************************************** |
|
* |
|
* 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 <stdio.h> |
|
#include <stdint.h> |
|
#include <string.h> |
|
#include <stdlib.h> |
|
#include <assert.h> |
|
|
|
/* 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, *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); |
|
|
|
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); |
|
} |
|
} |
|
pu1_prv += 8; |
|
pu1_top += 8; |
|
pu1_bot += 8; |
|
pu1_out += 8; |
|
} |
|
} |
|
} |
|
return IDEINT_ERROR_NONE; |
|
}
|
|
|