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.
425 lines
13 KiB
425 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 = 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;
|
|
}
|