blob: bdd3268f0ffe75f20b3253d1324eeeb5a1f13cbb [file] [log] [blame]
/******************************************************************************
*
* 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_utils.c
*
* @brief
* This file contains the definitions of the core processing of the de
* interlacer.
*
* @author
* Ittiam
*
* @par List of Functions:
* ideint_weave_pic()
* init_bob_indices()
* ideint_weave_blk()
* ideint_spatial_filter()
*
* @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"
/**
*******************************************************************************
*
* @brief
* Weaves two fields to produce a frame
*
* @par Description
* Weaves two fields to produce a frame
*
* @param[in] ps_src_top
* Top field source
*
* @param[in] ps_src_bot
* Bottom field source
*
* @param[in] ps_dst_frm
* Destination frame
*
* @returns
* 0 on Success
*
* @remarks
*
*******************************************************************************
*/
WORD32 ideint_weave_pic(icv_pic_t *ps_src_top,
icv_pic_t *ps_src_bot,
icv_pic_t *ps_dst_frm,
WORD32 start_row,
WORD32 num_rows)
{
UWORD8 *pu1_src, *pu1_dst;
WORD32 i, j, num_comp;
icv_pic_t *ps_src_fld;
WORD32 fld;
icv_pic_t *ps_src_flds[2];
num_comp = 3;
ps_src_flds[0] = ps_src_top;
ps_src_flds[1] = ps_src_bot;
for(fld = 0; fld < 2; fld++)
{
ps_src_fld = ps_src_flds[fld];
for(i = 0; i < num_comp; i++)
{
WORD32 src_strd;
WORD32 dst_strd;
WORD32 comp_row_start, comp_row_end;
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_dst_frm->ai4_ht[i]);
pu1_src = ps_src_fld->apu1_buf[i];
pu1_dst = ps_dst_frm->apu1_buf[i];
src_strd = ps_src_fld->ai4_strd[i];
dst_strd = ps_dst_frm->ai4_strd[i];
/* If source field is bottom, increment destination */
pu1_dst += fld * dst_strd;
/* In case input and output are pointing to same buffer, then no need to copy */
if((pu1_src != pu1_dst) || ((2 * dst_strd) != src_strd))
{
pu1_dst += ps_dst_frm->ai4_strd[i] * comp_row_start;
pu1_src += ps_src_fld->ai4_strd[i] * comp_row_start / 2;
for(j = comp_row_start; j < comp_row_end; j += 2)
{
memcpy(pu1_dst, pu1_src, ps_dst_frm->ai4_wd[i]);
pu1_dst += ps_dst_frm->ai4_strd[i] * 2;
pu1_src += ps_src_fld->ai4_strd[i];
}
}
}
}
return 0;
}
/**
*******************************************************************************
*
* @brief
* Weaves a 8x8 block
*
* @par Description
* Weaves a 8x8 block from two fields
*
* @param[in] pu1_top
* Top field source
*
* @param[in] pu1_bot
* Bottom field source
*
* @param[in] pu1_dst
* Destination
*
* @param[in] dst_strd
* Destination stride
*
* @param[in] src_strd
* Source stride
*
* @returns
* 0 on success
*
* @remarks
*
*******************************************************************************
*/
WORD32 ideint_weave_blk(UWORD8 *pu1_top,
UWORD8 *pu1_bot,
UWORD8 *pu1_dst,
WORD32 dst_strd,
WORD32 src_strd,
WORD32 wd,
WORD32 ht)
{
WORD32 j;
for(j = 0; j < ht; j += 2)
{
memcpy(pu1_dst, pu1_top, wd);
pu1_dst += dst_strd;
pu1_top += src_strd;
memcpy(pu1_dst, pu1_bot, wd);
pu1_dst += dst_strd;
pu1_bot += src_strd;
}
return 0;
}
/**
*******************************************************************************
*
* @brief
* Copy a boundary block and pad
*
* @par Description
* Copies a block on one of the boundaries and pads
*
* @param[in] pu1_top
* Top field source
*
* @param[in] pu1_bot
* Bottom field source
*
* @param[in] pu1_pad
* Padded destination
*
* @param[in] cur_strd
* Stride for pu1_top and pu1_bot
*
* @param[in] row
* Current block's row
*
* @param[in] col
* Current block's column
*
* @param[in] num_blks_y
* Number of blocks in Y direction
*
* @param[in] num_blks_x
* Number of blocks in X direction
* @returns
* None
*
* @remarks
*
*******************************************************************************
*/
void ideint_pad_blk(UWORD8 *pu1_top,
UWORD8 *pu1_bot,
UWORD8 *pu1_pad,
WORD32 cur_strd,
WORD32 row,
WORD32 col,
WORD32 num_blks_y,
WORD32 num_blks_x,
WORD32 blk_wd,
WORD32 blk_ht)
{
WORD32 i;
WORD32 num_cols, num_rows;
UWORD8 *pu1_dst;
UWORD8 *pu1_src_top;
UWORD8 *pu1_src_bot;
num_rows = blk_ht + 4;
num_cols = blk_wd + 4;
pu1_src_top = pu1_top - cur_strd - 2;
pu1_src_bot = pu1_bot - cur_strd - 2;
pu1_dst = pu1_pad;
if(0 == col)
{
num_cols -= 2;
pu1_dst += 2;
pu1_src_top += 2;
pu1_src_bot += 2;
}
if(0 == row)
{
num_rows -= 2;
pu1_dst += 2 * (BLK_WD + 4);
pu1_src_top += cur_strd;
pu1_src_bot += cur_strd;
}
if((num_blks_x - 1) == col)
num_cols -= 2;
if((num_blks_y - 1) == row)
num_rows -= 2;
for(i = 0; i < num_rows; i += 2)
{
memcpy(pu1_dst, pu1_src_top, num_cols);
pu1_dst += (BLK_WD + 4);
memcpy(pu1_dst, pu1_src_bot, num_cols);
pu1_dst += (BLK_WD + 4);
pu1_src_top += cur_strd;
pu1_src_bot += cur_strd;
}
/* Pad Left */
if(0 == col)
{
for(i = 0; i < (BLK_HT + 4); i++)
{
WORD32 ofst = i * (BLK_WD + 4) + 2;
pu1_pad[ofst - 1] = pu1_pad[ofst];
pu1_pad[ofst - 2] = pu1_pad[ofst];
}
}
/* Pad right */
if((num_blks_x - 1) == col)
{
for(i = 0; i < (BLK_HT + 4); i++)
{
WORD32 ofst = i * (BLK_WD + 4) + 2 + blk_wd - 1;
WORD32 size = (BLK_WD - blk_wd) + 2;
/* Padding on right should include padding for boundary
* blocks when width is non-multiple of 8
*/
memset(&pu1_pad[ofst + 1], pu1_pad[ofst], size);
}
}
/* Pad Top */
if(0 == row)
{
WORD32 src_ofst = 2 * (BLK_WD + 4);
WORD32 dst_ofst = 0;
memcpy(pu1_pad + dst_ofst, pu1_pad + src_ofst, (BLK_WD + 4));
src_ofst += (BLK_WD + 4);
dst_ofst += (BLK_WD + 4);
memcpy(pu1_pad + dst_ofst, pu1_pad + src_ofst, (BLK_WD + 4));
}
/* Pad Bottom */
if((num_blks_y - 1) == row)
{
WORD32 src_ofst = (0 + blk_ht) * (BLK_WD + 4);
WORD32 dst_ofst = (1 + blk_ht) * (BLK_WD + 4);
WORD32 size = (BLK_HT - blk_ht) + 2;
/* Padding on bottom should include padding for boundary
* blocks when height is non-multiple of 8
*/
for(i = 0; i < size; i++)
{
memcpy(pu1_pad + dst_ofst, pu1_pad + src_ofst, (BLK_WD + 4));
dst_ofst += (BLK_WD + 4);
}
}
}
/**
*******************************************************************************
*
* @brief
* Performs spatial edge adaptive filtering
*
* @par Description
* Performs spatial edge adaptive filtering by detecting edge direction
*
* @param[in] pu1_src
* Source buffer
*
* @param[in] pu1_out
* Destination buffer
*
* @param[in] src_strd
* Source stride
*
* @param[in] out_strd
* Destination stride
* @returns
* None
*
* @remarks
*
*******************************************************************************
*/
void ideint_spatial_filter(UWORD8 *pu1_src,
UWORD8 *pu1_out,
WORD32 src_strd,
WORD32 out_strd)
{
WORD32 i;
WORD32 j;
WORD32 k;
/*********************************************************************/
/* This loop is for the two halves inside the 8x4 block. */
/*********************************************************************/
for(k = 0; k < 2; k++)
{
WORD32 adiff[3] = {0, 0, 0};
WORD32 shift;
WORD32 dir_45_le_90, dir_45_le_135, dir_135_le_90;
UWORD8 *pu1_row_1, *pu1_row_2, *pu1_dst;
/*****************************************************************/
/* Direction detection */
/*****************************************************************/
pu1_row_1 = pu1_src;
pu1_row_2 = pu1_src + src_strd;
/*****************************************************************/
/* Calculating the difference along each of the 3 directions. */
/*****************************************************************/
for(j = 0; j < SUB_BLK_HT; j ++)
{
for(i = 0; i < SUB_BLK_WD; i++)
{
adiff[0] += ABS_DIF(pu1_row_1[i], pu1_row_2[i]); /* 90 */
adiff[1] += ABS_DIF(pu1_row_1[i - 1], pu1_row_2[i + 1]); /* 135 */
adiff[2] += ABS_DIF(pu1_row_1[i + 1], pu1_row_2[i - 1]); /* 45 */
}
pu1_row_1 += src_strd;
pu1_row_2 += src_strd;
}
/*****************************************************************/
/* Applying bias, to make the diff comparision more robust. */
/*****************************************************************/
adiff[0] *= EDGE_BIAS_0;
adiff[1] *= EDGE_BIAS_1;
adiff[2] *= EDGE_BIAS_1;
/*****************************************************************/
/* comapring the diffs */
/*****************************************************************/
dir_45_le_90 = (adiff[2] <= adiff[0]);
dir_45_le_135 = (adiff[2] <= adiff[1]);
dir_135_le_90 = (adiff[1] <= adiff[0]);
/*****************************************************************/
/* Direction selection. */
/*****************************************************************/
shift = 0;
if(1 == dir_45_le_135)
{
if(1 == dir_45_le_90)
shift = 1;
}
else
{
if(1 == dir_135_le_90)
shift = -1;
}
/*****************************************************************/
/* Directional interpolation */
/*****************************************************************/
pu1_row_1 = pu1_src + shift;
pu1_row_2 = pu1_src + src_strd - shift;
pu1_dst = pu1_out;
for(j = 0; j < SUB_BLK_HT; j++)
{
for(i = 0; i < SUB_BLK_WD; i++)
{
pu1_dst[i] = (UWORD8)AVG(pu1_row_1[i], pu1_row_2[i]);
}
pu1_row_1 += src_strd;
pu1_row_2 += src_strd;
pu1_dst += out_strd;
}
pu1_out += SUB_BLK_WD;
pu1_src += SUB_BLK_WD;
}
}